// ==UserScript==
// @name             顶点PMS优化
// @version          2025-12-01
// @description      顶点PMS网页汉化
// @author           alone
// @license          MIT
// @match            *://cowork.apexsoft.com.cn/*
// @match            *://192.168.0.63:8888/*
// @icon             
// @grant            GM_registerMenuCommand
// @grant            GM_unregisterMenuCommand
// @grant            GM_notification
// @grant            GM_info
// @grant            GM_setValue
// @grant            GM_getValue
// @grant            GM_deleteValue
// @grant            GM_openInTab
// @grant            GM_addStyle
// @grant            GM_getResourceText
// @run-at           document-end

// @require          https://gitee.com/zw95cn/my-scripts/raw/master/js/libs/jquery/3.5.1/jquery.min.js
// @require          https://gitee.com/zw95cn/my-scripts/raw/master/js/libs/pako/2.0.3/pako.min.js
// @require          https://gitee.com/zw95cn/my-scripts/raw/master/js/libs/ElementGetter.js
// @require          https://gitee.com/zw95cn/my-scripts/raw/master/js/libs/sweetalert2.js

// @require          https://gitee.com/zw95cn/my-scripts/raw/master/js/libs/myLib.js?timestamp=1757491359
// @resource         customCSS https://gitee.com/zw95cn/my-scripts/raw/master/js/libs/css/myCss.css?timestamp=1757491359

// @homepageURL      https://gitee.com/zw95cn/my-scripts/blob/master/js/youhou
// @updateURL        https://gitee.com/zw95cn/my-scripts/raw/master/js/youhou/apexPMS.user.js
// ==/UserScript==

// ============================ 全局函数
var updateDate = GM_info.script.version

const css = GM_getResourceText("customCSS");
GM_addStyle(css);

const configIdList = [
  {
    group: '产品接口文档',
    id: 'addAjustWidth',
    title: '接口定义：添加扩展按钮；修改日志美化',
    name: '接口文档编辑添加扩展按钮',
  },
  {
    group: '产品接口文档',
    id: 'perfAmsDocTree',
    title: '产品接口文档树添加工具栏，图标修正，样式优化',
    name: '产品接口文档左侧树结构优化',
  },
  {
    group: '产品接口文档',
    id: 'perfAmsCodeEditor',
    title: '修正接口代码编辑器错误',
    name: '修正接口代码编辑器错误',
  },
  {
    group: '数据模型文档',
    id: 'pmsLogLargeFont',
    title: '文档树添加工具栏，图标修正，样式优化',
    name: '模型接口文档左侧树结构优化',
  },
  {
    group: '数据模型文档',
    id: 'pmsChildTaskPerf',
    title: '模型定义：添加扩展按钮；修改日志美化',
    name: '模型文档编辑添加扩展按钮',
  },
  { group: '数据模型文档', id: 'pmsDocumentPagePerf', title: '优化代码编辑器样式、字体', name: '优化模型代码编辑器' },
  { group: '任务界面', id: 'pmsWholeFontPerf', title: '日志大字体', name: '任务日志字体调大' },
  { group: '任务界面', id: 'perfDataModelDocTree', title: '子任务列表优化', name: '子任务列表优化' },
  { group: '在线文档界面', id: 'addAjustWidthToModel', title: '去除无用图标', name: '文档界面优化' },
  { group: '全局', id: 'perfMonacoEditor', title: '字体样式优化', name: '字体样式优化' },
]

const scriptInfo = GM_info.script,
  locHost = location.host,
  locHref = location.href,
  locHash = location.hash,
  locPath = location.pathname

let t = {
  showNotice(msg) {
    GM_notification({
      text: msg,
      title: scriptInfo.name,
      image: scriptInfo.icon,
      highlight: false,
      silent: false,
      timeout: 1500,
    })
  },

  clog() {
    for (let m of arguments) {
      if (void 0 !== m) console.log(m)
    }
    console.groupEnd()
  },

  get(name, def) {
    return GM_getValue(name, def)
  },

  set(name, value) {
    GM_setValue(name, value)
  },

  setIfAbsent(name, value) {
    if (GM_getValue(name, null) == null) GM_setValue(name, value)
  },

  delete(name) {
    GM_deleteValue(name)
  },

  registerMenu(title, func) {
    return GM_registerMenuCommand(title, func)
  },

  unregisterMenu(menuID) {
    GM_unregisterMenuCommand(menuID)
  },

  open(url, options = { active: true, insert: true, setParent: true }) {
    GM_openInTab(url, options)
  },

  http(link, s = false) {
    return link.startsWith('http') ? link : (s ? 'https://' : 'http://') + link
  },

  title(a, mark = '') {
    if (a.title) a.title += '\n' + mark + decodeURIComponent(a.href)
    else a.title = mark + decodeURIComponent(a.href)
  },

  hashcode(l = location) {
    return l.hash.slice(1)
  },

  search(l = location, p = 'password') {
    let args = l.search.slice(1).split('&')
    for (let a of args) {
      if (a.includes(p + '=')) return a.replace(p + '=', '')
    }
    return ''
  },

  clean(src, str) {
    for (let s of str) {
      src = src.replace(s, '')
    }
    return src
  },

  loop(func, times) {
    let tid = setInterval(() => {
      if (times <= 0) clearInterval(tid)
      func()
      this.clog(times)
      times--
    }, 100)
  },

  confirm(title, yes, no = () => {}, deny = false) {
    let option = {
      toast: true,
      showCancelButton: true,
      position: 'center',
      title,
      confirmButtonText: '是',
      cancelButtonText: '否',
      showDenyButton: deny,
      denyButtonText: '取消',
      customClass: {
        popup: 'lh-popup',
        content: 'lh-content',
        closeButton: 'lh-close',
      },
    }
    return Swal.fire(option).then((res) => {
      if (res.isConfirmed) yes()
      else if (res.isDismissed) no()
      else if (res.isDenied) deny()
    })
  },

  rand(min, max) {
    if (arguments.length == 1) (max = min), (min = 0)
    let random = Math.random(),
      randInt = Math.floor(random * (max + 1 - min)) + min
    return randInt
  },
}
// 注册配置弹窗
function registerMenu() {
  // 如果没设置值 默认为true
  configIdList.forEach((v) => {
    t.setIfAbsent(v.id, true)
  })

  function generateHtml(config) {
    let html = `<ul class="lh-menu">`

    // 用于跟踪当前分组
    let currentGroup = null

    config.forEach((item) => {
      if (item.group !== currentGroup) {
        // 如果分组变化，添加新的分组标题
        html += `<li class="lh-item lh-item-group">
                   <span>${item.group}</span>
                 </li>`
        currentGroup = item.group
      }
      // 添加功能项
      html += `<li class="lh-item">
                 <label title="${item.title}">
                   <input type="checkbox" id="${item.id}"/>
                   <span class="checkBoxText">${item.name}</span>
                 </label>
               </li>`
    })

    html += `</ul>`
    return html
  }

  function showSettings() {
    let html = generateHtml(configIdList)

    Swal.fire({
      title: '配置',
      html,
      footer: `<div class="lh-footer">
							   <span>${formatDateVersionToDesc(updateDate)}更新</span>
							 </div>`,
      showCloseButton: true,
      showConfirmButton: true,
      showDenyButton: true,
      showCancelButton: true,
      confirmButtonText: '保存',
      denyButtonText: '全部关闭',
      cancelButtonText: '恢复默认',
      customClass: {
        popup: 'lh-popup',
        content: 'lh-content',
        closeButton: 'lh-close',
      },
      didOpen: () => {
        configIdList.forEach((v) => {
          $(`#${v.id}`).prop('checked', t.get(v.id) == true, false)
        })
      },
    }).then((result) => {
      // 根据设置展示控件选中状态

      if (result.isConfirmed) {
        // 保存配置并刷新
        configIdList.forEach((v) => {
          t.set(v.id, $(`#${v.id}`).prop('checked') || false)
        })
        createAlert('已保存，稍后刷新', 'success', 2000)
        setTimeout(() => {
          window.location.reload()
        }, 2000)
      } else if (result.isDenied) {
				// 全部关闭
        configIdList.forEach((v) => {
          t.set(v.id, false)
        })
        createAlert('已全部关闭，稍后刷新', 'success', 2000)
        setTimeout(() => {
          window.location.reload()
        }, 2000)

      } else if (result.dismiss === Swal.DismissReason.cancel){
				// 重置为全部开启
        configIdList.forEach((v) => {
          t.delete(v.id)
        })
        createAlert('已重置，稍后刷新', 'success', 2000)
        setTimeout(() => {
          window.location.reload()
        }, 2000)
			}
    });
  }
  GM_addStyle(
    deGzip(
      `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`
    )
  )
  t.registerMenu('配置', showSettings)
}

// 个性函数部分  ================================================================================
var zTree1, sheetIframe

// 获取表格范围文字内容
function getRangeText(luckysheet, setting) {
  const sheet = luckysheet.getSheetData()

  if (!sheet || sheet.length === 0) {
    return ''
  }

  // 如果没有提供range，使用默认选区
  const processRange = setting?.range ||
    luckysheet.getluckysheet_select_save()[0] || {
      row: [0, sheet.length - 1],
      column: [0, Math.max(...sheet.map((row) => (row ? row.length : 0))) - 1 || 25],
    }

  let result = ''
  const startRow = Math.max(0, processRange.row[0])
  const endRow = Math.min(sheet.length - 1, processRange.row[1])
  const startCol = Math.max(0, processRange.column[0])
  const endCol = Math.min(
    Math.max(...sheet.map((row) => (row ? row.length : 0))) - 1 || 25,
    processRange.column[1]
  )

  for (let r = startRow; r <= endRow; r++) {
    let rowText = ''
    for (let c = startCol; c <= endCol; c++) {
      const cell = sheet[r] && sheet[r][c]
      const cellText = cell ? cell.m || cell.v || '' : ''
      rowText += cellText + '\t'
    }
    result += rowText.slice(0, -1) + '\n'
  }

  return result.slice(0, -1)
}

function findObjectById(objects, targetId, currentObject = null) {
  // 如果当前层级对象不为空且其id等于目标id，则返回当前对象
  if (currentObject && currentObject.id === targetId) {
    return currentObject
  }

  // 遍历对象数组
  for (const obj of objects) {
    // 如果当前对象的id匹配目标id，则返回当前对象
    if (obj.id === targetId) {
      return obj
    }

    // 如果当前对象有children属性，递归搜索children数组
    if (obj.children && obj.children.length > 0) {
      const foundObject = findObjectById(obj.children, targetId)
      // 如果在子数组中找到对象，返回找到的对象
      if (foundObject) {
        return foundObject
      }
    }
  }

  // 如果遍历完数组都没有找到，返回null
  return null
}

// 接口定义：添加一键调整合适宽度；接口定义说明优化;修改日志美化
function addAjustWidth() {
  // 增强，在sheet中增加调整宽度的按钮
  elmGetter.each('#apiDefineSheet #luckysheet-wa-editor', document, (waEditor) => {
    // 分割线
    var sepDivHtml = `<div id='toolbar-separator-merge-cell' class='luckysheet-toolbar-separator luckysheet-inline-block' style='user-select: none;'/>`
    var sepDiv1 = createDivByHtml(sepDivHtml)
    var sepDiv2 = createDivByHtml(sepDivHtml)

    // ----------------------------------------- 优化操作手感
    // 去除鼠标移动事件，移除编辑框范围就会取消编辑状态
    var sheetIframe = window.frameElement
    var ls = sheetIframe.contentWindow.luckysheet
    var lsjs = ls.toJson()
    // 取消原本功能：移除单元格取消编辑状态
    lsjs.hook.sheetMousemove = null

    // 接口文档页签，按Ctrl+s 保存接口文档，第一次发现时，默认添加保存功能，然后添加一个监视器，如果接口文档tab不显示了，则说明切到了其他页签，则去掉保存事件
    function handleKeyDown(e) {
      if (e.ctrlKey && e.key === "s") {
        e.preventDefault();
        saveApiDefine();
      }
    }
    if(document.querySelector('#apiDefineSheet')?.style.display!=='none'){
      document.addEventListener("keydown", handleKeyDown);
    }
    let isSaveEnabled = true;
    const targetElement = document.querySelector("#apiDefineSheet");
    let lastDisplay = window.getComputedStyle(targetElement).display;
    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === "attributes") {
          const currentDisplay = window.getComputedStyle(targetElement).display;
          // 如果值发生改变
          if (currentDisplay !== lastDisplay) {
            if (currentDisplay === "none") {
              if (isSaveEnabled) {
                document.removeEventListener("keydown", handleKeyDown);
                isSaveEnabled = false;
              }
            } else {
              if (!isSaveEnabled) {
                document.addEventListener("keydown", handleKeyDown);
                isSaveEnabled = true;
              }
            }

            lastDisplay = currentDisplay;
          }
        }
      });
    });
    const config = {
      attributes: true,
      attributeFilter: ['style', 'class']
    };
    observer.observe(targetElement, config);

		// 取消不能合并的限制
		if (lsjs?.hook?.setRangeMergeBefore) {
      var originFuncStr = 'function (type,range) {\n                    //console.log("setRangeMergeBefore",type,range)\n                    //return checkUpdateBefore(luckysheet.getSheet().index,range[0])\n                    if(!loadingSheet && luckysheet.getSheet().index=="apiDemo") {   //此sheet禁止合并单元格\n                        if (range==null) return true;\n                        if(range[0].row[0] <= 6 && type=="mergeAll"){   //前7行禁止合并\n                            return false;\n                        }else if(range[0].column[0]>3 && type=="mergeAll"){ //第4列之后禁止合并\n                            return false;\n                        }\n                    }\n                    return  true;\n                }';
      if (lsjs?.hook?.setRangeMergeBefore.toString() == originFuncStr) {
        lsjs.hook.setRangeMergeBefore = function (type,range) {
					return true;
				};
			} else if (lsjs?.hook?.setRangeMergeBefore.toString().includes('setRangeMergeBefore')) {
				createAlert('表格方法 luckysheet.toJson().hook.setRangeMergeBefore 版本有变动，请更新脚本代码', 'error')
				return
			}
		}

		// 取消范围更新时的编辑限制
		if (lsjs?.hook?.rangeEditBefore) {
      var originFuncStr = 'function (range,data) {\n                    //console.log("rangeEditBefore",range,data)\n                    return checkUpdateBefore(luckysheet.getSheet().index,range[0])\n                }';
      if (lsjs?.hook?.rangeEditBefore.toString() == originFuncStr) {
        lsjs.hook.rangeEditBefore = function (range,data) {
					return true;
				};
			} else if (lsjs?.hook?.rangeEditBefore.toString().includes('setRangeMergeBefore')) {
				createAlert('表格方法 luckysheet.toJson().hook.rangeEditBefore 版本有变动，请更新脚本代码', 'error')
				return
			}
		}
		// 取消范围更新时的编辑限制
		if (lsjs?.hook?.rangeClearBefore) {
      var originFuncStr = 'function (range) {\n                    //console.log("rangeClearBefore",range);\n                    return checkUpdateBefore(luckysheet.getSheet().index,range[0]);\n                }';
      if (lsjs?.hook?.rangeClearBefore.toString() == originFuncStr) {
        lsjs.hook.rangeClearBefore = function (range) {
					return true;
				};
			} else if (lsjs?.hook?.rangeClearBefore.toString().includes('setRangeMergeBefore')) {
				createAlert('表格方法 luckysheet.toJson().hook.rangeClearBefore 版本有变动，请更新脚本代码', 'error')
				return
			}
		}
		// 取消范围更新时的编辑限制
		if (lsjs?.hook?.cellUpdateBefore) {
      var originFuncStr = 'function (r,c,v,isRefresh) {\n                    //console.log("cellUpdateBefore",luckysheet.getSheet(), r, c, v, isRefresh)\n                    if(!checkUpdateBefore(luckysheet.getSheet().index, {row:[r,r],column:[c,c]})){\n                        return false;\n                    }\n                    return checkDataValidity(luckysheet.getSheet().index, {row:r,column:c},v);\n\n\n                }';
      if (lsjs?.hook?.cellUpdateBefore.toString() == originFuncStr) {
        lsjs.hook.cellUpdateBefore = function (r,c,v,isRefresh) {
					return checkDataValidity(luckysheet.getSheet().index, {row:r,column:c},v)
				};
			} else if (lsjs?.hook?.cellUpdateBefore.toString().includes('setRangeMergeBefore')) {
				createAlert('表格方法 luckysheet.toJson().hook.cellUpdateBefore 版本有变动，请更新脚本代码', 'error')
				return
			}
		}

		// 取消范围更新时的编辑限制
		if (lsjs?.hook?.cellEditBefore) {
      var originFuncStr = 'function (range){\n                    //console.log("cellEditBefore", luckysheet.getSheet(),range)\n                    return checkUpdateBefore(luckysheet.getSheet().index, range[0]);\n                }';
      if (lsjs?.hook?.cellEditBefore.toString() == originFuncStr) {
        lsjs.hook.cellEditBefore = function (range) {
					return true;
				};
			} else if (lsjs?.hook?.cellEditBefore.toString().includes('setRangeMergeBefore')) {
				createAlert('表格方法 luckysheet.toJson().hook.cellEditBefore 版本有变动，请更新脚本代码', 'error')
				return
			}
		}

		// 取消范围粘贴时的编辑限制
		if (lsjs?.hook?.rangePasteBefore) {
      var originFuncStr = `function (range,originData,pasteData) {\n                    //console.log("rangePasteBefore",range,originData.types,originData.getData('text/plain'),pasteData)\n                    //console.log(originData.getData('text/html'),typeof originData.getData('text/html'))\n                    if (range){\n                        if(!loadingSheet && luckysheet.getSheet().index=="apiDemo") {\n                            if (range[0].row[0] <= 6) return false;\n                        }\n                    }\n                }`;
      if (lsjs?.hook?.rangePasteBefore.toString() == originFuncStr) {
        lsjs.hook.rangePasteBefore = function (range,originData,pasteData) {
						return true;
				};
			} else if (lsjs?.hook?.rangePasteBefore.toString().includes('apiDemo')) {
				createAlert('表格方法 luckysheet.toJson().hook.rangePasteBefore 版本有变动，请更新脚本代码', 'error')
				return
			}
		}

		// 调整校验，避免调整样式报错
		if (checkDataValidity){
			var originFuncStr = 'function checkDataValidity(index,range,data){\n        if(isEmpty(index) || isEmpty(range)){\n            return false;\n        }\n        try {\n            var status = true;\n            var r = (typeof range.row)=="object"?range.row[0]:range.row;\n            var end_r = (typeof range.row)=="object"?range.row[1]:range.row;\n            var c = (typeof range.column)=="object"?range.column[0]:range.column;\n            var end_c = (typeof range.column)=="object"?range.column[1]:range.column;\n            var v = (typeof data)=="object"?data[0][0]:data;   //提取第一个元素的值\n            if(luckysheet.getSheet().order==0 && r==0 && c==1) {\n                if(isEmpty(v)){\n                    //alert("功能码或功能名称不能为空");\n                    return false;\n                }\n                if (!reg.test(v)) {\n                    alert("功能码"+v+"不能包含特殊字符和汉字,不能已数字开头");\n                    return false;\n                }else{\n                    function filter(node) {\n                        return ((node.apiCode+"").toLowerCase()==v.toLowerCase() && node.id!=apiInfo.id);\n                    }\n                    if(zTree.getNodesByFilter(filter, true)){\n                        alert("接口重名");\n                        return false;\n                    }\n                }\n            }\n        }catch (e){\n            luckysheet.toolTip("info", "错误", "数据合法性判断异常:" + e);\n            return false;\n        }\n        return true;\n    }';

			if (checkDataValidity.toString() == originFuncStr) {
				checkDataValidity = function(index,range,data) {
					if(isEmpty(index) || isEmpty(range)){
							return false;
					}
					try {
							var status = true;
							var r = (typeof range.row)=="object"?range.row[0]:range.row;
							var end_r = (typeof range.row)=="object"?range.row[1]:range.row;
							var c = (typeof range.column)=="object"?range.column[0]:range.column;
							var end_c = (typeof range.column)=="object"?range.column[1]:range.column;

						  var v ;
							if (Array.isArray(data) && typeof data === 'object') {
								v = data[0][0]
							} else {
								v = data
							}
							if(luckysheet.getSheet().order==0 && r==0 && c==1) {
									if(isEmpty(v)){
											return false;
									}
									if (!reg.test(v)) {
											createAlert("功能码"+v+"不能包含特殊字符和汉字,不能已数字开头", 'error')
											return false;
									}else{
											function filter(node) {
													return ((node.apiCode+"").toLowerCase()==v.toLowerCase() && node.id!=apiInfo.id);
											}
											if(zTree.getNodesByFilter(filter, true)){
													createAlert("接口重名", 'error')
													return false;
											}
									}
							}
					}catch (e){
						  console.error("数据合法性判断异常:" + e);
							createAlert("数据合法性判断异常", 'error')
							return false;
					}
					return true;
				}
			} else if (checkDataValidity.toString().includes('var v = (typeof data)=="object"?data[0][0]:data;')) {
        createAlert('表格方法 checkDataValidity 版本有变动，请更新脚本代码', 'error')
        return
      }

		}

    // 移除表格区域，主动取消编辑状态
    document.querySelector('#apiDefineSheet').parentElement.addEventListener('mouseleave', function (e) {
      var inputBox = document.querySelector('#luckysheet-input-box')
      if (
        parseInt($('#luckysheet-input-box').css('top')) > 0 &&
        e.toElement != inputBox &&
        !inputBox.contains(e.toElement)
      )
        ls.exitEditMode()
    })

    // ----------------------------------------- 调整宽度和字体
    var ajstFontDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="调整宽度和字体" id="luckysheet-icon-fontformat" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-ziti" style="user-select: none;font-size: 14px; color:deepskyblue;font-weight: bold;">样</div> </div> </div> </div> </div>'
    )
    bindToolTip(ajstFontDiv);
    ajstFontDiv.addEventListener('click', function () {
      var colWidths = {"0":82,"1":154,"2":143,"3":94,"4":161,"5":62,"6":76,"7":178,"8":400,"9":276};
      var sheetIframe = window.frameElement
      var ls = sheetIframe.contentWindow.luckysheet
      ls.setColumnWidth(colWidths)

      // 调整字体为第一个字体()
      // var a0Value = ls.getCellValue(0, 0)
      // ls.setCellValue(0, 0, a0Value)

      if (ls.toJson()?.data[0]) {
        const rowCnt = ls.toJson().data[0].row
        const columnCnt = ls.toJson().data[0].column
        // 第一行除功能码；第二行以下
        ls.setRangeFormat('ff', 2, {
          range: [
            { row: [0, 0], column: [0, 0] },
            { row: [0, 0], column: [2, columnCnt - 1] },
            { row: [1, rowCnt - 1], column: [0, columnCnt - 1] },
          ],
        })
        ls.setRangeFormat('fs', 11, {
          range: [
            { row: [0, 0], column: [0, 0] },
            { row: [0, 0], column: [2, columnCnt - 1] },
            { row: [1, rowCnt - 1], column: [0, columnCnt - 1] },
          ],
        })
        var rowHeights = {};
        for(var i = 0;i <= rowCnt - 1;i++){
					// 检查第6行第2列是否有内容
					if (!(ls.getCellValue(5, 1) && ls.getCellValue(5, 1).toString().trim() !== '' && i === 5)) {
						rowHeights[i] = 20;
					} else {
						rowHeights[i] = ls.getRowHeight([i])[i];
					}
        }
        ls.setRowHeight(rowHeights);

        // 功能码只能用这个函数设置样式
        ls.setCellFormat(0, 1, 'ff', 2)
        ls.setCellFormat(0, 1, 'fs', 11)
        createAlert('已调整宽度和字体', 'success', 2000)
      }
    })
    // ----------------------------------------- 使用应用接口模版
    var copyAppTmplDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="使用应用接口模版" id="luckysheet-icon-paintformat" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-" style="user-select: none;font-size: 14px; color:#ff8000;font-weight: bold;">应</div> </div> </div> </div> </div>'
    )
    bindToolTip(copyAppTmplDiv);
    copyAppTmplDiv.addEventListener('click', function () {
      var sheetIframe = window.frameElement
      var ls = sheetIframe.contentWindow.luckysheet

      Swal.fire({
        title: '是否将当前接口替换为应用模版？',
        showCloseButton: false,
        showConfirmButton: true,
        confirmButtonText: '确认',
        showCancelButton: true,
        cancelButtonText: '取消',
        icon: 'warning',
      }).then((result) => {
        if (result.isConfirmed) {
          let appCode = `app${Date.now()}`
          let appSheetDateGzip = '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';

          // 将功能码调整为时间戳后缀的
          // 取原excel数据，排除第一个
          var lsdata = luckysheet.getAllSheets().slice(1)
          // 取固定数据的第一个(接口数据)
          var newData = JSON.parse(deGzip(appSheetDateGzip).replaceAll('applicationTemplate', appCode))[0]


          ls.updataSheet({ data: [newData, ...lsdata] })
          setTimeout(() => {
            var a0Value = ls.getCellValue(0, 1)
            ls.setCellValue(0, 1, a0Value)
          }, 300)

					// 更新最近更新时间
					ls.setCellValue(0, 7, formatDate(new Date()))

          createAlert('已使用应用接口模版，请修改内容', 'success')
        } /*else if (result.dismiss === Swal.DismissReason.cancel) {
          createAlert('已取消','info')
        }*/
      })

    })

    // ----------------------------------------- 使用领域接口模版
    var copyDomainTmplDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="使用领域接口模版" id="luckysheet-icon-paintformat" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-" style="user-select: none;font-size: 14px; color:#ffcb00;font-weight: bold;">领</div> </div> </div> </div> </div>'
    )
    bindToolTip(copyDomainTmplDiv);
    copyDomainTmplDiv.addEventListener('click', function () {
      var ls = sheetIframe.contentWindow.luckysheet;

      Swal.fire({
        title: '是否将当前接口替换为领域模版？',
        showCloseButton: false,
        showConfirmButton: true,
        confirmButtonText: '确认',
        showCancelButton: true,
        cancelButtonText: '取消',
        icon: 'warning',
      }).then((result) => {
        if (result.isConfirmed) {
        let domainCode = `domain${Date.now()}`
        const domainSheetDateGzip =
          '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'
        // 将功能码调整为时间戳后缀的
        // 取原excel数据，排除第一个
        var lsdata = luckysheet.getAllSheets().slice(1)
        // 取固定数据的第一个(接口数据)
        var newData = JSON.parse(deGzip(domainSheetDateGzip).replaceAll('domainTemplate', domainCode))[0]
        ls.updataSheet({ data: [newData, ...lsdata] })

        setTimeout(() => {
          var a0Value = ls.getCellValue(0, 1)
          ls.setCellValue(0, 1, a0Value)
        }, 300)

					// 更新最近更新时间
				ls.setCellValue(0, 7, formatDate(new Date()))

        createAlert('已使用领域接口模版，请修改内容', 'success')
        } /*else if (result.dismiss === Swal.DismissReason.cancel) {
          createAlert('已取消','info')
        }*/
      });

    })

    // ----------------------------------------- 添加接口标记文字到接口名前面
    var addTagDiv = createDivByHtml(
      `<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="设置文档标签" id="luckysheet-icon-fontformat" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-ziti" style="user-select: none;font-size: 14px; color:black;font-weight: bold;">标</div> </div> </div> </div> </div>`
    )
    bindToolTip(addTagDiv);
    addTagDiv.addEventListener('click', async function () {
      var sheetIframe = window.frameElement
      var ls = sheetIframe.contentWindow.luckysheet
      // 定义所有选项名称
      const options = {
        废弃: {
          未使用: '未使用',
          待弃用: '待弃用',
          需求取消: '需求取消',
        },
        重点: {
          规划中: '规划中',
          待补充: '待补充',
          待重构: '待重构',
        },
      }
			function setMemo(selOpt) {
        if (selOpt) {
          if (selOpt !== 'delete') {
            // 非取消场景
            ls.setCellValue(2, 4, selOpt)
            createAlert(`状态设为${selOpt}`, 'success' , 1500)
          } else {
            ls.setCellValue(2, 4, '正常')
            createAlert(`状态恢复正常` , 1500)
          }
        }
      }
      const { value: selOpt } = await Swal.fire({
        title: '添加快捷备注',
        input: 'select',
        inputOptions: options,
        inputPlaceholder: '请选择',
        inputValidator: (value) => {
          if (!value) {
            return '请选择一项!'
          }
        },
        showDenyButton: true,
        showCancelButton: true,
        confirmButtonText: '确定',
        denyButtonText: '恢复正常',
        cancelButtonText: '取消',
      })

      if (typeof selOpt == 'string') {
        setMemo(selOpt)
      } else if (selOpt == false) {
        setMemo('delete')
      }
    })
    // ----------------------------------------- 转换所选区域驼峰<=>下划线
    var tranCamelCaseDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="所选区域驼峰<=>下划线" id="luckysheet-icon-tranEngCase" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-kuandu" style="user-select: none;font-size: 14px; color:#FF8000">_a</div> </div> </div> </div> </div>'
    )
    bindToolTip(tranCamelCaseDiv);
    tranCamelCaseDiv.addEventListener('click', function () {
      var sheetIframe = window.frameElement
      var ls = sheetIframe.contentWindow.luckysheet
      var currSheet = ls.getSheet()
      if (currSheet) {
        tranEngCamelCaseRange(ls, null)
        createAlert('已转换驼峰/下划线', 'success')
      }
    })
    // ----------------------------------------- 删除选中行和下面的所有行
    var deleteRowDiv = createDivByHtml(
      `<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="删除选中行下面的所有行" id="luckysheet-icon-fontformat" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-ziti" style="user-select: none;font-size: 14px; color:red;font-weight: bold;">删</div> </div> </div> </div> </div>`
    )
    bindToolTip(deleteRowDiv);
    deleteRowDiv.addEventListener('click', async function () {
      const sheetIframe = window.frameElement;
      const ls = sheetIframe.contentWindow.luckysheet;
      const sheetData = ls.toJson().data[0];

      const rowCnt = sheetData.row;  // 总行数
      const columnCnt = sheetData.column;  // 总列数
      const selectRanges = ls.getRange();

      let maxSelectedRow = -1;

      // 校验选区必须是完整的行，并找出最大选中行
      for (const range of selectRanges) {
        const [rowStart, rowEnd] = range.row;
        const [colStart, colEnd] = range.column;

        if (
          range.row.length === 2 &&
          range.column.length === 2 &&
          rowStart <= rowEnd &&
          colStart === 0 &&
          colEnd === columnCnt - 1
        ) {
          maxSelectedRow = Math.max(maxSelectedRow, rowEnd);
        } else {
          createAlert('请选中要删除的起始行，必须选中整行！', 'warning');
          return;
        }
      }

      if (maxSelectedRow === -1) {
        createAlert('当前选区数据有误', 'warning');
        console.warn('当前选区数据有误', JSON.stringify(selectRanges));
        return;
      }

      // 计算要删除的行范围
      const deleteStartRow = maxSelectedRow;
      const deleteEndRow = rowCnt - 1;

      if (deleteStartRow > deleteEndRow) {
        createAlert('没有需要删除的行', 'info', 1500);
        return;
      }

      var confirmText = deleteStartRow + 1 === deleteEndRow + 1 ?  `第 ${deleteStartRow + 1}行` : `第 ${deleteStartRow + 1} 行到第 ${deleteEndRow + 1} 行`;

      // 确认删除
      Swal.fire({
        title: `将删除${confirmText}，是否确认？`,
        icon: 'warning',
        showConfirmButton: true,
        confirmButtonText: '确认',
        showCancelButton: true,
        cancelButtonText: '取消',
      }).then((result) => {
        if (result.isConfirmed) {
          // 逐行删除，避免索引错位（从下往上删）
          for (let row = deleteEndRow; row >= deleteStartRow; row--) {
            ls.deleteRow(row, row);
          }

          // 更新表格数据
          const newData = {
            ...sheetData,
            row: deleteStartRow,  // 保留的行数
            data: sheetData.data.slice(0, deleteStartRow),
          };
          ls.updataSheet({ data: [newData, ...ls.getAllSheets().slice(1)] });

          createAlert(`已删除从第 ${deleteStartRow + 1} 行到第 ${deleteEndRow + 1} 行`, 'success', 1500);
        }
      });
    });

    // ----------------------------------------- 添加模版内容按钮
		var copyTempDiv = createDivByHtml(`<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="复制当前文档为模版" id="luckysheet-icon-fontformat" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-ziti" style="user-select: none;font-size: 14px; color:brown;font-weight: bold;">模</div> </div> </div> </div>
      <div class="w-e-select-list" style="display: none;">
        <ul>
          <li data-value="apiDocTemp1" style="font-size: 14px; ">
            <span>复制为应用接口模版</span>
          </li>
          <li data-value="apiDocTemp2" style="font-size: 14px; ">
            <span>复制为领域接口模版</span>
          </li>
          <li data-value="apiDocTemp3" style="font-size: 14px; ">
            <span>复制列宽属性</span>
          </li>
        </ul>
      </div>
    </div>`);
    bindToolTip(copyTempDiv);
    // 获取按钮和下拉菜单元素
    var selectList = copyTempDiv.querySelector('.w-e-select-list');
    // 点击隐藏、展开下拉
    copyTempDiv.addEventListener('click', function () {
      event.stopPropagation(); // 阻止事件冒泡
      if (selectList.style.display === 'none') {
          selectList.style.display = 'block';
      } else {
          selectList.style.display = 'none';
      }
    });
    // 每个选项事件
    selectList.querySelectorAll('li').forEach(function(item) {
        item.addEventListener('click', function() {
            var value = this.getAttribute('data-value');

            // 根据不同的选项添加不同的HTML内容
            var sheetIframe = window.frameElement;
            var ls = sheetIframe.contentWindow.luckysheet;
            var lsData = ls.toJson();

            if (value === 'apiDocTemp1') {
              var excelData = JSON.parse(JSON.stringify([lsData.data[0]]));
              var apiCode = excelData[0]?.data[0][1]?.v||'';
              var tmplCode = 'applicationTemplate';
              if(apiCode){
                excelData[0].data[0][1].v = tmplCode;
                excelData[0].data[0][1].m = tmplCode;
                excelData[0].data[3][1].v = excelData[0]?.data[3][1]?.v.replace(apiCode, tmplCode);
                excelData[0].data[3][1].m = excelData[0]?.data[3][1]?.v;
              }

              var tempGzipText = gzip(JSON.stringify(excelData));
              copyRichText(tempGzipText);
              createAlert('已复制为应用接口模版','success',1500)
            } else if (value === 'apiDocTemp2') {
              var excelData = JSON.parse(JSON.stringify([lsData.data[0]]));
              var apiCode = excelData[0]?.data[0][1]?.v||'';
              var tmplCode = 'domainTemplate';
              if(apiCode){
                excelData[0].data[0][1].v = tmplCode;
                excelData[0].data[0][1].m = tmplCode;
                excelData[0].data[3][1].v = excelData[0]?.data[3][1]?.v.replace(apiCode, tmplCode);
                excelData[0].data[3][1].m = excelData[0]?.data[3][1]?.v;
              }

              var tempGzipText = gzip(JSON.stringify(excelData));
              copyRichText(tempGzipText);
              createAlert('已复制为领域接口模版','success',1500)
            } else if (value === 'apiDocTemp3') {
              var colLen = lsData.data[0].config.columnlen;
              copyRichText(JSON.stringify(colLen));
              createAlert('已复制列宽属性','success',1500)
            }

            setTimeout(()=>{
              selectList.style.display = 'none'; // 添加内容后隐藏下拉列表
            },200);
        });
    });

    // 确保 document 的点击事件监听器只被添加一次
		if (!document.__dropdownClickListenerAdded) {
      document.addEventListener('click', function () {
          selectList.style.display = 'none';
      });
      document.__dropdownClickListenerAdded = true; // 标记已添加
    }

    // ----------------------------------------- 复制文档截图
    var copyScreenShotDiv = createDivByHtml(
      `<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="复制文档截图" id="luckysheet-icon-copyscreenshot" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-ziti" style="user-select: none;font-size: 14px; color:green;font-weight: bold;">图</div> </div> </div> </div> </div>`
    )
    bindToolTip(copyScreenShotDiv);
    copyScreenShotDiv.addEventListener('click', async function () {

      const sheetIframe = window.frameElement;
      const ls = sheetIframe.contentWindow.luckysheet;
      const sheetData = ls.toJson().data[0];
      const rowCnt = sheetData.row;  // 总行数
      const columnCnt = sheetData.column;  // 总列数

      // 确认是哪种方式
      Swal.fire({
        title: `请选择截图范围`,
        icon: 'warning',
        showConfirmButton: true,
        confirmButtonText: 'A~I列',
        showCancelButton: true,
        cancelButtonText: '取消',
        showDenyButton: true,
        denyButtonText: '选区',
      }).then((result) => {
        if (result.isConfirmed) {
          var allRange = {range:{row:[0,rowCnt-1],column:[0, Math.min(columnCnt-1, 8)]}};
          var altText = getRangeText(ls, allRange);
          copyRichText(luckysheet.getScreenshot(allRange), {type:'image',altText} );
          createAlert('已复制截图', 'success', 2000)
        } else if (result.isDenied) {
          var altText = getRangeText(ls);
          copyRichText(luckysheet.getScreenshot(), {type:'image',altText});
          createAlert('已复制选区截图', 'success', 2000)
        }
      });
    });


    waEditor.firstChild.nextElementSibling.nextElementSibling.setAttribute('data-tooltip', '保存')
    bindToolTip(waEditor.firstChild.nextElementSibling.nextElementSibling);
    waEditor.insertBefore(sepDiv2, waEditor.firstChild.nextElementSibling.nextElementSibling.nextElementSibling)
    waEditor.insertBefore(ajstFontDiv, sepDiv2)
    waEditor.insertBefore(tranCamelCaseDiv, sepDiv2)
    waEditor.insertBefore(addTagDiv, sepDiv2)
    waEditor.insertBefore(copyTempDiv, sepDiv2)
    waEditor.insertBefore(copyScreenShotDiv, sepDiv2)
    waEditor.insertBefore(deleteRowDiv, sepDiv2)
    waEditor.insertBefore(copyAppTmplDiv, ajstFontDiv)
    waEditor.insertBefore(copyDomainTmplDiv, ajstFontDiv)
    waEditor.insertBefore(sepDiv1, copyAppTmplDiv)
  })

	// 优化接口设计文档界面
	elmGetter.each('#editor-toolbar > .w-e-toolbar> .w-e-bar-item:nth-child(1)', document, (firstItem) =>{
    var apiDocToolbar = firstItem.parentElement;
    var dividerDiv = createDivByHtml(`<div class="w-e-bar-divider"></div>`);

    // 设计文档页签，按Ctrl+s 保存设计说明
    function handleKeyDown(e) {
      if (e.ctrlKey && e.key === "s") {
        e.preventDefault();
        editor && saveApiDesignDoc(editor.getHtml());
      }
    }
    if(document.querySelector('#apiDesignDoc')?.style.display!=='none'){
      document.addEventListener("keydown", handleKeyDown);
    }
    let isSaveEnabled = true;
      const targetElement = document.querySelector("#apiDesignDoc");
      let lastDisplay = window.getComputedStyle(targetElement).display;
      const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
          if (mutation.type === "attributes") {
            const currentDisplay = window.getComputedStyle(targetElement).display;
            // 如果值发生改变
            if (currentDisplay !== lastDisplay) {

              if (currentDisplay === "none") {
                if (isSaveEnabled) {
                  document.removeEventListener("keydown", handleKeyDown);
                  isSaveEnabled = false;
                }
              } else {
                if (!isSaveEnabled) {
                  document.addEventListener("keydown", handleKeyDown);
                  isSaveEnabled = true;
                }
              }

              lastDisplay = currentDisplay;
            }
          }
        });
      });
      const config = {
        attributes: true,
        attributeFilter: ['style', 'class']
      };
      observer.observe(targetElement, config);

		// 添加模版内容按钮
		var newToolDiv = createDivByHtml(`<div class="w-e-bar-item">
			<button type="button" class="select-button" data-menu-key="addDocTemp" style="user-select: none;font-size: 14px; color:blue">快捷<svg viewBox="0 0 1024 1024"><path d="M498.7 655.8l-197.6-268c-8.1-10.9-0.3-26.4 13.3-26.4h395.2c13.6 0 21.4 15.4 13.3 26.4l-197.6 268c-6.6 9-20 9-26.6 0z"></path></svg></button>
			<div class="w-e-select-list" style="display: none;">
				<ul>
					<li data-value="apiDocTemp1" style="font-size: 14px; ">
						<span data-value="apiDocTemp1">前后端说明</span>
					</li>
				</ul>
			</div>
		</div>`);
		// 获取按钮和下拉菜单元素
		var selectList = newToolDiv.querySelector('.w-e-select-list');
		// 点击隐藏、展开下拉
    newToolDiv.addEventListener('click', function () {
			event.stopPropagation(); // 阻止事件冒泡
			if (selectList.style.display === 'none') {
					selectList.style.display = 'block';
			} else {
					selectList.style.display = 'none';
			}
		});
		// 每个选项事件
		selectList.querySelectorAll('li').forEach(function(item) {
				item.addEventListener('click', function() {
						var value = this.getAttribute('data-value');

						// 根据不同的选项添加不同的HTML内容
						var htmlCont = '';
						var oldText = editor.getText();
						var oldHtml = editor.getHtml();
						var tempHtml = '';

						if (value === 'apiDocTemp1') {
								tempHtml = '<h2>后端</h2><p><br></p><h2>前端</h2><p><br></p>';
						} else if (value === 'apiDocTemp2') {
								tempHtml = '<p>其他模板</p>';
						}

						editor.setHtml(oldText === '' ? tempHtml : oldHtml + '<br>' + tempHtml);
						editor.focus();
						setTimeout(()=>{
							selectList.style.display = 'none'; // 添加内容后隐藏下拉列表
						},200);
				});
		});

		// 添加搜索替换弹窗按钮
		var searchReplaceBtn = createDivByHtml(`<div class="w-e-bar-item"><button type="button" class="select-button" data-menu-key="replaceText" style="user-select: none; color:blue">替换</button></div>`);

		searchReplaceBtn.addEventListener("click", function () {
				Swal.fire({
						title: "替换",
						html: `
								<div style="text-align:left;">
										<label>搜索：</label>
										<input type="text" id="findText" class="swal2-input" placeholder="查找内容">
										<label>替换：</label>
										<input type="text" id="replaceText" class="swal2-input" placeholder="替换内容">
										<div style="margin-top:10px;">
												<label><input type="checkbox" id="regexCheckbox"> 正则</label>
										</div>
								</div>
						`,
						showCancelButton: true,
						confirmButtonText: "确认",
						cancelButtonText: "取消",
						focusConfirm: false,
						preConfirm: () => {
								return new Promise((resolve) => {
									const findText = document.getElementById("findText").value.trim();
									const replaceText = document.getElementById("replaceText").value.trim();
									const useRegex = document.getElementById("regexCheckbox").checked;

									if (!findText) {
											Swal.showValidationMessage("❌ 请输入搜索内容！");
											resolve(false);
									} else {
											resolve({ findText, replaceText, useRegex });
									}
							});
        		}
				}).then((result) => {
						if (result.isConfirmed) {

								let content = editor.getHtml(); // 获取编辑器内容

								if (result.value.useRegex) {
										// 使用正则表达式替换
										try {
												const regex = new RegExp(result.value.findText, 'g');
												content = content.replace(regex, result.value.replaceText);
										} catch (e) {
											  createAlert("正则表达式无效，请检查输入！", 'error')
												return;
										}
								} else {
										// 普通文本替换
										content = content.replace(new RegExp(result.value.findText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), result.value.replaceText);
								}

								editor.setHtml(content); // 设置修改后的内容
								editor.focus();
						}
				});
		});

		// 确保 document 的点击事件监听器只被添加一次
		if (!document.__dropdownClickListenerAdded) {
				document.addEventListener('click', function () {
						selectList.style.display = 'none';
				});
				document.__dropdownClickListenerAdded = true; // 标记已添加
		}

    var orgiDiverDiv = apiDocToolbar.firstChild.nextElementSibling.nextElementSibling.nextElementSibling;

    apiDocToolbar.insertBefore(newToolDiv, orgiDiverDiv);
    apiDocToolbar.insertBefore(searchReplaceBtn, orgiDiverDiv);
    apiDocToolbar.insertBefore(dividerDiv, newToolDiv);

	});

  GM_addStyle(`
    /* 优化表格里的字体 */
    body{
        font-family: inherit;
    }
    /* 优化接口说明样式 */
    .w-e-text-container [data-slate-editor] {
      padding: 0px 10px 20px 10px !important;
    }
    #changeTime{
      font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif !important;
    }
		/* 文档编辑下拉框样式修复*/
    .w-e-select-list{
      z-index: 1001 !important; /* 比表格调整公式栏再高一层 */
    }
		.w-e-select-list ul {
      padding-left: 0px;
		}
		.w-e-select-list ul li {
      list-style: none;
      padding: 7px 25px 7px 25px !important;
		}
  `);
}
// 产品接口文档树添加工具栏，图标修正，样式优化
var count = 1
function getCurrApiNodeTop(id) {
  var container = document.getElementById(id)
  var targetItem = document.querySelector('li:has(>.curSelectedNode)')
  var scrollToPosition = null
  if (targetItem) {
    // 计算目标元素的中心位置
    scrollToPosition = targetItem.offsetTop - container.clientHeight / 2
  } else {
    // 如果没有选中，则尝试定位当前excel对应的接口
    var ls = sheetIframe.contentWindow.luckysheet
    if (ls) {
      var apiCode = ls.getCellValue(0, 1, null)
      targetItem = document.querySelector(`li:has(>a[title*='/${apiCode}'])`)
      if (targetItem) {
        targetItem.querySelector('a>span').click()
        scrollToPosition = targetItem.offsetTop - container.clientHeight / 2
      }
    }
  }
  if (targetItem) {
    if (id == 'apiTree') {
      secNodeAddHoverDom(targetItem.id, zTree.getNodeByTId(targetItem.id))
    } else if (id == 'modelTree') {
      secModelNodeAddHoverDom(targetItem.id, zTree.getNodeByTId(targetItem.id))
    }
  }

  return { pos: scrollToPosition, dom: targetItem }
}
function posiToCurrSelectedNode(id) {
  zTree.selectNode(zTree.getNodeByParam('id', id), false, false)
  setTimeout(() => {
    var obj = getCurrApiNodeTop(zTree.setting.treeId)
    if (obj.dom && obj.pos) {
      document.getElementById(zTree.setting.treeId).scrollTop = obj.pos
    }
  }, 200)
}
/* 选中的叶子节点增加加新节点的按钮 */
function secNodeAddHoverDom(treeId, treeNode) {
  // if((treeNode.isParent==false && treeNode.pId!=null ) || authType==0) return false;
  if (treeNode.isParent == true || authType == 0) return false
  if (treeNode.editNameFlag || $('#addBtn_' + treeNode.tId).length > 0) return
  var sObj = $('#' + treeNode.tId + '_span')
  var addStr =
    "<span class='button add' id='addBtn_" +
    treeNode.tId +
    "' tId='" +
    treeNode.tId +
    "' title='add node' onfocus='this.blur();'></span>"
  sObj.after(addStr)

  var btn = $('#addBtn_' + treeNode.tId, $('#apiTree'))
  if (btn)
    btn.bind('click', function () {
      //新增叶子，并移动到当前节点下方
      var pNode = zTree.getNodeByTId(treeNode.parentTId)
      var now = new Date()
      var time = now.toLocaleString().substring(11, 20).replaceAll(':', '').padStart(4, '0') //截取时间
      var id = Date.parse(now) / 1000
      var newApi = 'Api3653_' + time
      var newNode = { id: id, pId: pNode.id, name: newApi, apiName: newApi, apiCode: newApi }
      newNode = saveApiTree('add', null, newNode, pNode, 'nodeAdd', null)

      // 移动到当前节点下方
      setTimeout(() => {
        var tNode = zTree.getNodesByParam('id', treeNode.id)
        var node = zTree.getNodesByParam('id', id)
        if (tNode.length == 1 && node.length == 1) {
          saveApiTree('move', null, node[0], tNode[0], 'next', false)
          setTimeout(() => {
            posiToCurrSelectedNode(id)
          }, 200)
        }
      }, 400)
      return false
    })
}
function perfAmsDocTree() {
  // 接口树增强，增加扩展按钮
  elmGetter.each('#apiList', document, (apiList) => {
    sheetIframe = window.frameElement
    var toolBarDiv = createDivByHtml(`<div id='apiListToolbar' style= 'margin-bottom:-5px'/>`)

    apiList.insertBefore(toolBarDiv, apiList.firstChild)

    // 折叠所有
    var btnCollApseAll = createDivByHtml(
      `<button type="button" id="btn_collapseAll" style="font-size: 12px">折叠</button>`
    )
    btnCollApseAll.addEventListener('click', function () {
      sheetIframe.contentWindow.postMessage({ type: 'collapseAll' }, '/')
    })

    toolBarDiv.appendChild(btnCollApseAll)

    // 展开一级
    var btnExpandFirst = createDivByHtml(
      `<button type="button" id="btn_expandAll" style="font-size: 12px">展开一级</button>`
    )
    btnExpandFirst.addEventListener('click', function () {
      // 关闭二级
      document
        .querySelectorAll('#apiTree>li>ul>li>span.center_open, #apiTree>li>ul>li>span.bottom_open')
        .forEach((v) => v.click())
      // 展开一级
      document
        .querySelectorAll('#apiTree>li>span.roots_close, #apiTree>li>span.center_close, #apiTree>li>span.bottom_close')
        .forEach((v) => v.click())
    })

    toolBarDiv.appendChild(btnExpandFirst)

    // 展开全部
    var btnExpandAll = createDivByHtml(
      `<button type="button" id="btn_expandAll" style="font-size: 12px">展开全部</button>`
    )
    btnExpandAll.addEventListener('click', function () {
      zTree.expandAll(true)
    })

    toolBarDiv.appendChild(btnExpandAll)

    // 刷新
    var btnRefresh = createDivByHtml(`<button type="button" id="btn_refresh" style="font-size: 12px">刷新</button>`)
    btnRefresh.addEventListener('click', function () {
      zTree.expandAll(true)
      count = 1
      refreshApiList(sheetIframe.contentWindow.appId, sheetIframe.contentWindow.appBranch)
    })

    toolBarDiv.appendChild(btnRefresh)

    // 定位
    var btnPosiDiv = createDivByHtml(
      `<button type="button" disabled id="btn_posi" style="font-size: 12px">定位</button>`
    )
    btnPosiDiv.addEventListener('click', function () {
      if (apiInfo && apiInfo.id) {
        posiToCurrSelectedNode(apiInfo.id)
      }
      /*var obj = getCurrApiNodeTop('apiTree')
			if (obj.dom && obj.pos) {
				document.getElementById(id).scrollTop = obj.pos
			}*/
    })

    toolBarDiv.appendChild(btnPosiDiv)
  })

  // 重写刷新接口列表函数，刷新后重新加载文件夹子接口数量
  elmGetter.each('#apiTree', document, (apiTree) => {
    // 定义属性变化的回调函数
    var observerCallback = function (mutationsList) {
      for (let mutation of mutationsList) {
        if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
					setTimeout(()=>{
						var btnPosi = document.querySelector('#btn_posi')
						if (getCurrApiNodeTop('apiTree').dom) {
							btnPosi.disabled = false
						} else {
							btnPosi.disabled = true
						}
					},200);

        }
      }
    }
    // 创建一个观察者实例并配置观察选项
    var observer = new MutationObserver(observerCallback)
    var observerConfig = {
      attributes: true,
      attributeFilter: ['class'], // 仅监控class属性
      subtree: true,
    }
    // 开始观察ul元素及其子元素的class属性变动
    observer.observe(apiTree, observerConfig)

    sheetIframe.contentWindow.onload = function () {
      // 刷新树时计算树数量
      var _1 = refreshApiList
      refreshApiList = function (arg1, arg2) {
        _1(arg1, arg2)
        zTree = sheetIframe.contentWindow.zTree
        // zTree.expandAll(true)
        fillAllNodeNameWithChildCount()
        if (count == 1) {
          // zTree.expandAll(false)
          count++
        }
      }

      // 树变动后，自动跳到对应节点
      /*var _2 = saveApiTree
      saveApiTree = function (event, treeId, treeNode, targetNode, moveType, isCopy) {
        var trueMoveType = moveType
        if (moveType === 'nodeAdd') trueMoveType = null
        else if (event === 'delete') {
          refreshApiList(appId, appBranch)
          var node = zTree.getNodeByParam('id', treeNode.id, null)
          if (targetNode) {
            //前面refreshTree重新构造了tree，必须重新获取一次
            targetNode = zTree.getNodeByParam('id', targetNode.id, null)
          }
          //这个操作让删除节点后，展开父节点，选择到删除节点的上一个节点，如果没有则展示到父节点
          if (node.getPreNode()) {
            targetNode = node.getPreNode()
          } else if (node.getParentNode()) {
            targetNode = node.getParentNode()
          }
        }
        var result = _2(event, treeId, treeNode, targetNode, trueMoveType, isCopy)
        if (result && event !== 'delete') {
          // 定位到指定节点
          setTimeout(() => {
            posiToCurrSelectedNode(result.id)
          }, 200)
        } else if (event == 'delete') {
          if (targetNode) {
            setTimeout(() => {
              posiToCurrSelectedNode(targetNode.id)
            }, 200)
          }
        }
        return result
      }*/

      var _2 = saveApiTree
      if(saveApiTree){
        var originFuncStr = `function saveApiTree(event, treeId, treeNode, targetNode, moveType,isCopy) {\n        refreshApiList(appId,appBranch);\n        var node =  zTree.getNodeByParam("id",treeNode.id, null);\n        //console.log(event,treeNode,node,targetNode, moveType,isCopy)\n        if(treeNode) {\n            //前面refreshTree重新构造了tree，必须重新获取一次\n            node =  zTree.getNodeByParam("id",treeNode.id, null);\n            if(treeNode.env!=undefined){\n                node.env  = treeNode.env;\n            }\n        }\n        if(targetNode) {\n            //前面refreshTree重新构造了tree，必须重新获取一次\n            targetNode = zTree.getNodeByParam("id", targetNode.id, null);\n            //console.log(event,treeNode,node,targetNode, moveType,isCopy)\n        }else{\n            targetNode = zTree.getNodeByParam("id", treeNode.pId, null);\n        }\n        if(event=="add"){\n            zTree.addNodes(targetNode,treeNode);\n        }else if(event=="delete") {\n            targetNode = zTree.getNodeByParam("id", treeNode.pId, null);    //这个操作让删除节点后，展开父节点\n            zTree.removeNode(treeNode,false)\n        }else if(event=="update"){\n            if(treeNode.isParent) {\n                node.name = treeNode.name;\n            }else{\n                node.name = treeNode.apiName + "/" + treeNode.apiCode;\n                node.apiCode = treeNode.apiCode;\n                node.apiName = treeNode.apiName;\n                node.openScope = treeNode.openScope||'内部';\n            }\n            zTree.updateNode(node);\n        }else if(event=="move") {\n            if(targetNode) {\n                targetNode = zTree.getNodeByTId(targetNode.tId);\n            }else if(!node.isParent){\n                return node;\n            }\n            var dragNode = zTree.getNodeByTId(node.tId);\n            if (targetNode) {\n                zTree.moveNode(targetNode, dragNode, moveType, false);\n            } else if (dragNode.isParent) {\n                zTree.moveNode(null, dragNode, "next", false);\n            }\n        }\n\n        function simplifyTree(treeNodes) {\n            treeNodes.forEach(function (node, pIdx, array) {\n                delete (treeNodes[pIdx]).zAsync;\n                delete (treeNodes[pIdx]).check_Focus;\n                delete (treeNodes[pIdx]).checked;\n                delete (treeNodes[pIdx]).editNameFlag;\n                delete (treeNodes[pIdx]).nocheck;\n                delete (treeNodes[pIdx]).chkDisabled;\n                delete (treeNodes[pIdx]).isHover;\n                delete (treeNodes[pIdx]).isAjaxing;\n                delete (treeNodes[pIdx]).checkedOld;\n                delete (treeNodes[pIdx]).isHidden;\n                delete (treeNodes[pIdx]).halfCheck;\n                delete (treeNodes[pIdx]).check_Child_State;\n                delete (treeNodes[pIdx]).open;\n                delete (treeNodes[pIdx]).isOpen;\n                delete (treeNodes[pIdx]).parentTId;\n                delete (treeNodes[pIdx]).tId; //tId在每次刷新tree后都会自动重新生成\n                (treeNodes[pIdx])["searchName"] = treeNodes[pIdx].name+","+treeNodes[pIdx].openScope;\n                if (treeNodes[pIdx]["children"] != undefined && treeNodes[pIdx]["children"].length > 0) {\n                    simplifyTree(treeNodes[pIdx]["children"]);\n                }\n            });\n            return treeNodes;\n        }\n        zNodes = simplifyTree(zTree.getNodes());  //剔除多余信息\n        $.ajax({\n            url: "apiCommonService.jsp?MOD=saveApiList",\n            type: "POST",\n            data: {appId: appId,appBranch:encodeURIComponent(appBranch), apiList: encodeURIComponent(JSON.stringify(zNodes))},\n            async:false,\n            dataType: "JSON",\n            success: function (ret) {\n                if (ret && ret['CODE'] && parseInt(ret['CODE']) > 0) {\n                    $("#luckysheet_info_detail_save").text("已保存");\n                } else {\n                    alert("保存接口定义出错," + ret['NOTE']);\n                    return null;\n                }\n            }, error: function (text, msg, e) {\n                alert("会话已过期!");\n                return null;\n            }\n        });\n\n        refreshApiList(appId,appBranch);\n\n        if(targetNode) {\n            //前面refreshTree重新构造了tree，必须重新获取一次\n            targetNode = zTree.getNodeByParam("id", targetNode.id, null);\n            if(!targetNode.open){\n                zTree.expandNode(targetNode, true, false, true);\n            }\n        }\n        isChangeTree = false;\n        if(["add","update","move"].includes(event)) {\n            node = zTree.getNodeByParam("id", treeNode.id, null);\n        }\n        return node;\n\n    }`;
        if (originFuncStr === saveApiTree.toString()) {
          saveApiTree = function saveApiTree(event, treeId, treeNode, targetNode, moveType, isCopy) {
						var checkNodes = zTree.getCheckedNodes(true); //所有选中节点
						var checkChilds = checkNodes.filter((v) => !v.isParent); //所有选中子节点
						var singleParentAllSec = checkNodes.filter(
							(v) => v.isParent && v?.check_Child_State == 2
						); // 是否选中了单个目录下的所有节点
						function isParent(targetNode, node) {
							while (node) {
								if (node.id === targetNode.id) {
									return true;
								}
								node = node.getParentNode();
							}
							return false;
						}

						refreshApiList(appId, appBranch);
						var node = zTree.getNodeByParam("id", treeNode.id, null);
						//console.log(event,treeNode,node,targetNode, moveType,isCopy)
						if (treeNode) {
							//前面refreshTree重新构造了tree，必须重新获取一次
							node = zTree.getNodeByParam("id", treeNode.id, null);
							if (treeNode.env != undefined) {
								node.env = treeNode.env;
							}
						}
						if (targetNode) {
							//前面refreshTree重新构造了tree，必须重新获取一次
							targetNode = zTree.getNodeByParam("id", targetNode.id, null);
							//console.log(event,treeNode,node,targetNode, moveType,isCopy)
						} else {
							targetNode = zTree.getNodeByParam("id", treeNode.pId, null);
						}

						// 开头添加处理，如果移动多个节点
						// 获取所有子节点的父节点ID,由于代码运行到这里，前端的node已经有一个节点移动了，父目录会变成新目录，故需要筛选在选中nodes范围内的父节点
						const parentIds = new Set(checkNodes.filter((v) => !v.isParent).map(child => child.pId).filter(v=>checkNodes.some(x=>x.id === v)));
						// 如果子节点来自多个不同的父节点，则不允许移动
						if ( checkChilds.length > 1 && parentIds.size > 1) {
								createAlert("不支持跨目录移动多个接口", "error", 1500);
								return null;
						}

						// 如果选中了单个目录下的所有节点，则改为移动此目录
						if (
							singleParentAllSec.length == 1 &&
							checkNodes.filter((v) => v.isParent).length == 1 &&
							node.id != targetNode.id && parentIds
						) {
							createAlert("如果要移动整个目录节点，请选中目录进行拖拽", "warn");
							// return null;
						}

						// 判断选中的节点数量是否超过一个，如果超过一个，则批量移动（仅移动子节点）, 这是不管移动的是哪个节点，都会仅处理选中的节点
						if (checkChilds.length > 1 && event == "move") {
							// 移动多个节点
							if (targetNode) {
								targetNode = zTree.getNodeByTId(targetNode.tId);
							} else if (!node.isParent) {
								return node;
							}
							// 移动节点
							if (moveType === "inner" || moveType === "prev") {
								treeNode = checkChilds[0];
								// 顺序执行
								for (var i = 0; i < checkChilds.length; i++) {
									var eachNode = zTree.getNodeByParam("id", checkChilds[i].id, null);
									// 检查是否尝试将节点移动到自身或自己的子节点下

									zTree.moveNode(targetNode, eachNode, moveType);
								}
							} else {
								// 倒序执行
								treeNode = checkChilds[checkChilds.length - 1];
								for (var i = checkChilds.length - 1; i >= 0; i--) {
									var eachNode = zTree.getNodeByParam("id", checkChilds[i].id, null);
									// 检查是否尝试将节点移动到自身或自己的子节点下
									if (eachNode.id === targetNode.id || isParent(targetNode, eachNode)) {
										createAlert("不能将节点移动到自身或自己的子节点下！", "error", 1500);
										continue;
									}
									zTree.moveNode(targetNode, eachNode, moveType);
								}
							}
						} else {
							var trueMoveType = moveType;
							if (moveType === "nodeAdd") trueMoveType = null;
							else if (event === "delete") {
								refreshApiList(appId, appBranch);
								var node = zTree.getNodeByParam("id", treeNode.id, null);
								if (targetNode) {
									//前面refreshTree重新构造了tree，必须重新获取一次
									targetNode = zTree.getNodeByParam("id", targetNode.id, null);
								}
								//这个操作让删除节点后，展开父节点，选择到删除节点的上一个节点，如果没有则展示到父节点
								if (node.getPreNode()) {
									targetNode = node.getPreNode();
								} else if (node.getParentNode()) {
									targetNode = node.getParentNode();
								}
							}

							// 原始处理
							if (event == "add") {
								zTree.addNodes(targetNode, treeNode);
							} else if (event == "delete") {
								targetNode = zTree.getNodeByParam("id", treeNode.pId, null); //这个操作让删除节点后，展开父节点
								zTree.removeNode(treeNode, false);
							} else if (event == "update") {
								if (treeNode.isParent) {
									node.name = treeNode.name;
								} else {
									node.name = treeNode.apiName + "/" + treeNode.apiCode;
									node.apiCode = treeNode.apiCode;
									node.apiName = treeNode.apiName;
									node.openScope = treeNode.openScope || "内部";
								}
								zTree.updateNode(node);
							} else if (event == "move") {
								if (targetNode) {
									targetNode = zTree.getNodeByTId(targetNode.tId);
								} else if (!node.isParent) {
									return node;
								}
								var dragNode = zTree.getNodeByTId(node.tId);
								if (targetNode) {
									zTree.moveNode(targetNode, dragNode, moveType, false);
								} else if (dragNode.isParent) {
									zTree.moveNode(null, dragNode, "next", false);
								}
							}
						}

						function simplifyTree(treeNodes) {
							treeNodes.forEach(function (node, pIdx, array) {
								delete treeNodes[pIdx].zAsync;
								delete treeNodes[pIdx].check_Focus;
								delete treeNodes[pIdx].checked;
								delete treeNodes[pIdx].editNameFlag;
								delete treeNodes[pIdx].nocheck;
								delete treeNodes[pIdx].chkDisabled;
								delete treeNodes[pIdx].isHover;
								delete treeNodes[pIdx].isAjaxing;
								delete treeNodes[pIdx].checkedOld;
								delete treeNodes[pIdx].isHidden;
								delete treeNodes[pIdx].halfCheck;
								delete treeNodes[pIdx].check_Child_State;
								delete treeNodes[pIdx].open;
								delete treeNodes[pIdx].isOpen;
								delete treeNodes[pIdx].parentTId;
								delete treeNodes[pIdx].tId; //tId在每次刷新tree后都会自动重新生成
								treeNodes[pIdx]["searchName"] =
									treeNodes[pIdx].name + "," + treeNodes[pIdx].openScope;
								if (
									treeNodes[pIdx]["children"] != undefined &&
									treeNodes[pIdx]["children"].length > 0
								) {
									simplifyTree(treeNodes[pIdx]["children"]);
								}
							});
							return treeNodes;
						}
						zNodes = simplifyTree(zTree.getNodes()); //剔除多余信息
						$.ajax({
							url: "apiCommonService.jsp?MOD=saveApiList",
							type: "POST",
							data: {
								appId: appId,
								appBranch: encodeURIComponent(appBranch),
								apiList: encodeURIComponent(JSON.stringify(zNodes)),
							},
							async: false,
							dataType: "JSON",
							success: function (ret) {
								if (ret && ret["CODE"] && parseInt(ret["CODE"]) > 0) {
									$("#luckysheet_info_detail_save").text("已保存");
								} else {
									alert("保存接口定义出错," + ret["NOTE"]);
									return null;
								}
							},
							error: function (text, msg, e) {
								alert("会话已过期!");
								return null;
							},
						});

						refreshApiList(appId, appBranch);

						if (targetNode) {
							//前面refreshTree重新构造了tree，必须重新获取一次
							targetNode = zTree.getNodeByParam("id", targetNode.id, null);
							if (!targetNode.open) {
								zTree.expandNode(targetNode, true, false, true);
							}
						}

						isChangeTree = false;
						if (["add", "update", "move"].includes(event)) {
							node = zTree.getNodeByParam("id", treeNode.id, null);
						}
						// 结尾添加处理
						if (node && event !== "delete") {
							// 待ztree展开到指定节点后，处理滚动条到对应位置
							setTimeout(() => {
								posiToCurrSelectedNode(node.id);
							}, 200);
						} else if (event == "delete") {
							if (targetNode) {
								setTimeout(() => {
									posiToCurrSelectedNode(targetNode.id);
								}, 200);
							}
						}
						return node;
					}

        }else if (!checkDataValidity.toString().includes('开头添加处理，如果移动多个节点')) {
          createAlert('模型表格方法 saveApiTree 版本有变动，请更新脚本代码', 'error')
          return
        }
      }
			var _3 = saveApiDesignDoc
      saveApiDesignDoc = function (arg1) {
				// 保存换行为<br>，查询时再反向处理
				// 现在直接保存\r，查出来时会丢失换行
				arg1 = arg1.replaceAll('\n','<br>');
        _3(arg1);
				createAlert("已保存接口设计说明","success",1000);
      }

      // 重写保存接口定义方法，修复保存不了的问题
			var _4 = saveApiDefine
      if(saveApiDefine){
        var originFuncStr = `function saveApiDefine() {
        changeList.forEach(function(sheetIndex){
            let apiCode = "";
            let excel = luckysheet.getSheet({index:sheetIndex});
            let apiName = "";
            if(sheetIndex=="apiDemo") {
                apiName = luckysheet.getCellValue(1, 1,{order:0});
                apiCode = luckysheet.getCellValue(0, 1,{order:0});
                if(isEmpty(apiName)||isEmpty(apiCode)){
                    alert("功能码或功能名称不能为空");
                    return false;
                }
                if (!reg.test(apiCode)) {
                    alert("功能码不能包含特殊字符和汉字,不能已数字开头");
                    return false;
                }
                luckysheet.setCellValue(0, 4,"上次更新时间",{order:0,isRefresh:false});
                luckysheet.setCellValue(0, 6,(new Date()).toLocaleString(),{order:0,isRefresh:false});
                excel = luckysheet.getSheet({order:0});
            }else{
                apiCode = excel.index;
            }
            excel.celldata="";  //清除没用的数据,减小体积
            excel.luckysheet_select_save = [];
            excel.luckysheet_selection_range = [];
            //excel.index = apiInfo.apiCode;
            //去除临时数据,减小体积
            //for(var i in excel) excel[i].data = undefined
            var sheetfileString = encodeURIComponent(JSON.stringify(excel));
            var compressed = pako.gzip(sheetfileString); // 不使用{to: "string"}选项
            var arrayBuffer = compressed.buffer; // 获取ArrayBuffer
            var base64Data = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer))); // 转换为Base64字符串
            $.ajax({
                url: "apiCommonService.jsp?MOD=saveApiDefine",
                type: "POST",
                data: {appId: appId,appBranch:encodeURIComponent(appBranch), apiCode: apiCode, jsonExcel: base64Data},
                async:false,
                dataType: "JSON",
                success: function (ret) {
                    if (ret && ret['CODE'] && parseInt(ret['CODE']) > 0) {
                        $("#luckysheet_info_detail_save").text("已保存");
                    } else {
                        alert("保存接口定义出错," + ret['NOTE']);
                        return false;
                    }
                }, error: function (text, msg, e) {
                    alert("会话已过期!");
                    return false;
                }
            });
        });
        changeList=[];
        window.parent.postMessage({type: "changeApiStatus",status:false}, '/')
        if(isChangeTree){
            if(saveApiTree("update",null,apiInfo,null,null,null)==null) return false;
        }
        $("#luckysheet-icon-save", container).attr("style", "color:#abb0b5");
        return true;
    }`;
				if (originFuncStr === saveApiDefine.toString()) {
          saveApiDefine = function saveApiDefine() {
							changeList.forEach(function(sheetIndex){
									let apiCode = "";
									let excel = luckysheet.getSheet({index:sheetIndex});
									let apiName = "";
									if(sheetIndex=="apiDemo") {
											apiName = luckysheet.getCellValue(1, 1,{order:0});
											apiCode = luckysheet.getCellValue(0, 1,{order:0});
											if(isEmpty(apiName)||isEmpty(apiCode)){
													alert("功能码或功能名称不能为空");
													return false;
											}
											if (!reg.test(apiCode)) {
													alert("功能码不能包含特殊字符和汉字,不能已数字开头");
													return false;
											}
											luckysheet.setCellValue(0, 4,"上次更新时间",{order:0,isRefresh:false});
											luckysheet.setCellValue(0, 6,(new Date()).toLocaleString(),{order:0,isRefresh:false});
											excel = luckysheet.getSheet({order:0});
									}else{
											apiCode = excel.index;
									}
									excel.celldata="";  //清除没用的数据,减小体积
									excel.luckysheet_select_save = [];
									excel.luckysheet_selection_range = [];
									//excel.index = apiInfo.apiCode;
									//去除临时数据,减小体积
									//for(var i in excel) excel[i].data = undefined
									var sheetfileString = encodeURIComponent(JSON.stringify(excel));
									var compressed = pako.gzip(sheetfileString); // 不使用{to: "string"}选项
									var arrayBuffer = compressed.buffer; // 获取ArrayBuffer
									//var base64Data = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer))); // 转换为Base64字符串

									function arrayBufferToBase64(buffer) {
											let binary = '';
											const bytes = new Uint8Array(buffer);
											const len = bytes.byteLength;
											for (let i = 0; i < len; i++) {
													binary += String.fromCharCode(bytes[i]);
											}
											return window.btoa(binary);
									}

									const base64Data = arrayBufferToBase64(compressed);

									$.ajax({
											url: "apiCommonService.jsp?MOD=saveApiDefine",
											type: "POST",
											data: {appId: appId,appBranch:encodeURIComponent(appBranch), apiCode: apiCode, jsonExcel: base64Data},
											async:false,
											dataType: "JSON",
											success: function (ret) {
													if (ret && ret['CODE'] && parseInt(ret['CODE']) > 0) {
															$("#luckysheet_info_detail_save").text("已保存");
													} else {
															alert("保存接口定义出错," + ret['NOTE']);
															return false;
													}
											}, error: function (text, msg, e) {
													alert("会话已过期!");
													return false;
											}
									});
							});
							changeList=[];
							window.parent.postMessage({type: "changeApiStatus",status:false}, '/')
							if(isChangeTree){
									if(saveApiTree("update",null,apiInfo,null,null,null)==null) return false;
							}
							$("#luckysheet-icon-save", container).attr("style", "color:#abb0b5");
              createAlert("已保存接口","success",1000);
							return true;
					};
        }else if (!checkDataValidity.toString().includes('base64Data = btoa(binaryString)')) {
          createAlert('模型表格方法 saveApiDefine 版本有变动，请更新脚本代码', 'error')
          return
        }
			}

			/*var _4 = saveApiDefine
      saveApiDefine = function () {
        _4();
				createAlert("已保存接口","success",1000);
      }*/
      designApi = null;
			elmGetter.get('#apiDesign').then((apiDesign) => {
				function createNewEditor(apiCode){
            window.editor = E.createEditor({
                selector: '#editor-text-area',
                config: {
                    placeholder : '请输入内容',
                    readOnly:(authType==0?true:false),
                    spellcheck: false,
                    MENU_CONF: {
                        uploadImage: {
                            fieldName: 'your-fileName',
                            base64LimitSize: 5 * 1024 * 1024 // 5M 以下插入 base64
                        }
                    },
                    onChange(editor) {
                        if(apiInfo.apiName != undefined && !editor.isEmpty() && editor.history.undos.length > 0)
                        {
                            if(isNotEmpty(designApi)) return;
                            var undos = editor.history.undos;
                            //console.log(undos)
                            undos.forEach(function(v,idx,array){
                                //console.log(v,v[0].type)
                                if(v[0].type!="set_selection"){
                                    if(doc!=editor.getHtml()) {
                                        doc = editor.getHtml();
                                        designApi = apiCode;
                                        $("[data-menu-key='Save']", '#editor-toolbar').attr("style", "color:red");
                                    }
                                }
                            })
                        }else {
                            //console.log(editor.history.undos)
                            designApi = null;
                        }
                        window.parent.postMessage({type: "changeDocStatus",status:isNotEmpty(designApi)}, '/')
                    }
                }
            })
            window.toolbar = E.createToolbar({
                editor,
                selector: '#editor-toolbar',
                config: {
                    insertKeys: {
                        index: 0,
                        keys: ['Save'], // show menu in toolbar
                    },
                    excludeKeys: ["group-video","emotion"]
                }
            })

            return editor;
        }

				function readApiDesignDoc(appId, branch, apiCode) {
					$.ajax({
						url: "apiCommonService.jsp?MOD=readApiDesignDoc",
						type: "POST",
						data: {
							appId: appId,
							appBranch: encodeURIComponent(branch),
							apiCode: apiCode,
						},
						dataType: "JSON",
						async: false,
						success: function (ret) {
							if (ret && parseInt(ret.CODE) > 0) {
								doc = ret.RESULT;
								if (isNotEmpty(doc)) {
									doc = doc.replaceAll('<br>','\n');
								}
							} else {
								alert("读取文档出错," + ret["NOTE"]);
							}
						},
						error: function (text, msg, e) {
							alert("会话已过期!");
						},
					});
					if (editor) {
						editor.destroy();
						editor = null;
					}
					editor = createNewEditor(apiCode);
					editor.setHtml(doc);
					editor.history.redos = [];
					editor.history.undos = [];
					designApi = null;
				}
				function clickFunc(){

						window.parent.postMessage({type: "hideRightPanle"}, '/')
            var id = this.id;
						const lis = document.querySelectorAll("#apiDef > .pms_tab > ul > li");
						$(lis).removeClass("pms_tab_selected");
            $(this).addClass("pms_tab_selected");
            $("#luckysheet-input-box").hide();
            var tabPage = document.querySelectorAll(".tabPage");
            for(var i=0;i<tabPage.length;i++){
                //console.log(tabPage[i],tabPage[i].getAttribute("name"),id)
                if(tabPage[i].getAttribute("name")==id){
                    tabPage[i].style.display = "block"
                }else{
                    tabPage[i].style.display = "none"
                }
            }
					readApiDesignDoc(sheetIframe.contentWindow.appId,sheetIframe.contentWindow.appBranch,sheetIframe.contentWindow.apiInfo.apiCode);

				}
				apiDesign.addEventListener('click', clickFunc);
			});

			/*var _5 = readApiDesignDoc
      readApiDesignDoc = function readApiDesignDoc(appId,branch,apiCode) {
				// 保存换行为<br>，查询时再反向处理
				// 现在直接保存\r，查出来时会丢失换行
				arg1 = arg1.replaceAll('\n','<br>');
        _3(arg1);
				createAlert("已保存接口设计说明","success",1000);
      }*/

      // 修改接口文档的ztree自带函数
      const originalInit = sheetIframe.contentWindow.$.fn.zTree.init
      sheetIframe.contentWindow.$.fn.zTree.init = function (container, settings, zNodes) {
        const treeObj = originalInit.apply(this, arguments)
        if (!treeObj?.setting?.check?.enable) {
          treeObj.setting.check = {
            enable: true, // 启用复选框
            chkStyle: 'checkbox', // 样式：复选框（默认）
            chkboxType: { Y: 'ps', N: 'ps' }, // 父子联动勾选逻辑
            radioType: 'level',
            chkDisabledInherit: false,
            noCheckInherit: false,
            autoCheckTrigger: false,
          }
        }
        if (treeObj?.setting?.callback?.onClick) {
          var originFuncStr = `function selectApi(event, treeId, treeNode){\n        if(changeList.length>0){\n            let v = window.confirm("有修改还未保存，是否保存？");\n            if(v==true){\n                saveApiDefine();\n                if(isChangeTree){\n                    saveApiTree("update",null,apiInfo,null,null,null);\n                }\n            }else{\n                changeList = [];\n                window.parent.postMessage({type: "changeApiStatus",status:false}, '/')\n            }\n        }\n        $("#luckysheet-icon-save", container).attr("style", "color:#abb0b5");\n        if(isNotEmpty(designApi)){\n            let v = window.confirm("【"+apiInfo.name+"】设计说明还未保存，是否保存？");\n            if(v==true){\n                saveApiDesignDoc(editor.getHtml());\n            }else{\n                designApi = null;\n                window.parent.postMessage({type: "changeDocStatus",status:isNotEmpty(designApi)}, '/')\n            }\n        }\n        //console.log(event,treeId,treeNode);\n        if(treeNode==undefined) return;\n\n        apiInfo = treeNode; //zTree.getNodeByTId(treeNode.tId);\n        if( treeNode!=undefined && treeNode.isParent){\n            apiInfo["apiName"]="接口定义";\n            apiInfo["apiCode"]="apiDemo";\n        }\n        selectTab[0].click();\n        loadingSheet = true; //数据加载开始，允许所有单元格可编辑\n        bCanModifyTemplate = false;\n        $("#apiDefineSheet").css("pointer-events","none");  //冻结表格页面\n        $("#luckysheet-input-box").css("top",-1000) //这个是为了避免上次公式框内容带到下个sheet的单元格中\n        luckysheet.loadSheet({appId:appId,appBranch:encodeURIComponent(appBranch),apiCode:apiInfo.apiCode,type:"1"},0,null,\n            {success:function (sheet) {\n                /*$("#luckysheet-icon-save", container).attr("style", "color:#abb0b5");\n                changeList = [];\n                window.parent.postMessage({type: "changeApiStatus",status:false}, '/')\n                loadingSheet = false;    //数据加载结束\n                $("#apiDefineSheet").css("pointer-events","");  //激活表格页面\n                return;*/\n                //修正旧格式\n                var cellFormat = {bg:"#F9CB9C",fc:"#000000",ht: 0,vt: 0}\n                var bNewFormat = (luckysheet.getCellValue(4,0)=="服务路径" || luckysheet.getCellValue(3,0)=="URL路径")?true:false;\n                if(luckysheet.getCellValue(3,0)!="URL路径"){\n                    luckysheet.insertRow(3);\n                    luckysheet.setCellValue(3,0,"URL路径");   luckysheet.setCellFormat(3, 0,"bg",cellFormat.bg);luckysheet.setCellFormat(3, 0,"ht",cellFormat.ht);\n                    luckysheet.setCellValue(3,bNewFormat?5:4,"HTTP方法"); luckysheet.setCellFormat(3,bNewFormat?5:4,"bg",cellFormat.bg);luckysheet.setCellFormat(3,bNewFormat?5:4,"ht",cellFormat.ht);\n                    luckysheet.setCellValue(3,bNewFormat?7:6,"POST");\n                    luckysheet.setRangeMerge("horizontal",bNewFormat?{range:"B4:E4"}:{range:"B4:D4"});\n                    luckysheet.setRangeMerge("horizontal",bNewFormat?{range:"F4:G4"}:{range:"E4:F4"});\n                }\n                if(luckysheet.getCellValue(4,0)!="服务路径"){\n                    luckysheet.insertRow(4);\n                    luckysheet.setCellValue(4,0,"服务路径");    luckysheet.setCellFormat(4, 0,"bg",cellFormat.bg);luckysheet.setCellFormat(4, 0,"ht",cellFormat.ht);\n                    luckysheet.setCellValue(4,bNewFormat?5:4,"服务名");    luckysheet.setCellFormat(4, bNewFormat?5:4,"bg",cellFormat.bg);luckysheet.setCellFormat(4, bNewFormat?5:4,"ht",cellFormat.ht);\n                    luckysheet.setCellValue(4,bNewFormat?7:6,"");\n                    luckysheet.setRangeMerge("horizontal",{range:"B5:D5"});\n                    luckysheet.setRangeMerge("horizontal",{range:"E5:F5"});\n                }\n                var sheetdata = luckysheet.getSheetData();\n                var mc = sheetdata[4][0]["mc"];\n                if(!isEmpty(mc) && mc.hasOwnProperty("rs") && mc.rs>1) {  //第5行有合并单元格，要取消\n                    for(var i=0;i<mc["rs"]-1;i++) {\n                        luckysheet.deleteRow(5+i, 5+i);\n                    }\n                }\n                var mc = sheetdata[5][0]["mc"];\n                if(!isEmpty(mc) && mc.hasOwnProperty("rs") && mc.rs>1) {  //第6行有合并单元格，要取消\n                    for(var i=0;i<mc["rs"]-1;i++) {\n                        luckysheet.deleteRow(6+i, 6+i);\n                    }\n                }\n                if(!bNewFormat) {\n                    var v = luckysheet.getCellValue(6, 4);\n                    if(isEmpty(v) || !(v.includes("参数"))) {\n                        luckysheet.insertColumn(4);\n                        luckysheet.insertColumn(6);\n                        luckysheet.setCellValue(6, 4, "二级参数");  luckysheet.setCellFormat(6, 4,"bg",cellFormat.bg);\n                        luckysheet.setCellValue(6, 6, "二级类型");  luckysheet.setCellFormat(6, 6,"bg",cellFormat.bg);\n                        //luckysheet.cancelRangeMerge("horizontal",{range:"B1:D5"});\n                        luckysheet.setRangeMerge("horizontal", {range: "B1:E5"});\n\n                        luckysheet.deleteRange("left", {range: "H1:H5"});\n                        //luckysheet.cancelRangeMerge("horizontal",{range:"F1:H5"});\n                        luckysheet.setRangeMerge("horizontal", {range: "F1:G5"});\n\n\n                        luckysheet.setColumnWidth({7: 400});\n\n                        var rows = luckysheet.getSheetData().length;\n                        //luckysheet.cancelRangeMerge({range: "F7:H" + rows});\n                        v = luckysheet.getCellValue(6, 0);\n                        /*if (isEmpty(v)){\n                            luckysheet.deleteRow(6,6);\n                            v = luckysheet.getCellValue(6, 0);\n                        }*/\n                        if (isEmpty(v) || (!v.includes("入参") && !v.includes("参数"))) {\n                            luckysheet.setCellValue(6,0,"参数")\n                            v = luckysheet.getCellValue(6, 1);\n                            if (isEmpty(v) || (!v.includes("入参") && !v.includes("参数"))) {\n                                bCanModifyTemplate = true;\n                                luckysheet.toolTip("info", "错误", "表格第7行异常，第7行不能跨行，且第7行第1列必须是标识为[输入参数]，请修正!");\n                            }\n                        }\n                        v = luckysheet.getCellValue(6, 4);\n                        if(isEmpty(v) || !v.includes("参数")) luckysheet.setCellValue(6, 4, "二级参数");\n                        v = luckysheet.getCellValue(6, 6);\n                        if(isEmpty(v) || !v.includes("类型")) luckysheet.setCellValue(6, 6, "二级类型");\n                    }\n\n                    luckysheet.setRangeMerge("horizontal",{range:"B1:E1"});\n                    luckysheet.setRangeMerge("horizontal",{range:"B2:E2"});\n                    luckysheet.setRangeMerge("horizontal",{range:"B5:E5"});\n                }\n                var v = luckysheet.getCellValue(2, 0);\n                if(v!="开放范围"){\n                    luckysheet.setCellValue(2, 0, "开放范围");\n                    v = luckysheet.getCellValue(2, 1);\n                    luckysheet.setDataVerification({ "type": "dropdown", "value1": "内部,第三方,AI", "type2":true,"prohibitInput": true   }, {range:"B3:B3"});\n                    luckysheet.setCellValue(2, 1, v=="Y"?"第三方":"内部");\n                }\n                v = luckysheet.getCellValue(2, 3);\n                if(isEmpty(v)){\n                    if(sheetdata[2][1].hasOwnProperty("mc")) {\n                        luckysheet.cancelRangeMerge({range:"B3:E3"});\n                    }\n                    luckysheet.setRangeMerge("all",{range:"B3:C3"});\n                    luckysheet.setCellValue(2, 3, "状态"); luckysheet.setCellFormat(2, 3,"bg",cellFormat.bg);luckysheet.setCellFormat(2, 3,"fc",cellFormat.fc);luckysheet.setCellFormat(2, 3,"ht",cellFormat.ht);\n                    //luckysheet.setDataVerification({ "type": "dropdown", "value1": "正常,草稿,作废",   "prohibitInput": true   }, {range:"E3:E3"});\n                    v = luckysheet.getCellValue(1, 1);\n                    var status = "正常";\n                    if(!isEmpty(v)){\n                        if(v.startsWith("（")) {\n                            status = v.substr(1, v.indexOf("）")-1)\n                            luckysheet.setCellValue(1, 1,v.replace("（"+status+"）",""));\n                        }\n                    }\n                    apiInfo["status"] = status;\n                    luckysheet.setCellValue(2, 4, status);\n                }\n\n                v = luckysheet.getCellValue(3, 3);  //接口类型\n                if(isEmpty(v)){\n                    if(sheetdata[3][1].hasOwnProperty("mc")) {\n                        luckysheet.cancelRangeMerge({range:"B4:E4"});\n                    }\n                    luckysheet.setRangeMerge("all",{range:"B4:C4"});\n                    luckysheet.setCellValue(3, 3, "接口类型"); luckysheet.setCellFormat(3, 3,"bg",cellFormat.bg);luckysheet.setCellFormat(3, 3,"ht",cellFormat.ht);\n                    luckysheet.setDataVerification({ "type": "dropdown", "value1": "标准接口,编织接口",   "prohibitInput": true   }, {range:"E4:E4"});\n                    luckysheet.setCellValue(3, 4, "标准接口");\n                }\n                sheetdata = luckysheet.getSheetData()\n                var mc = sheetdata[4][4]["mc"];\n                if(!isEmpty(mc) && mc.hasOwnProperty("cs")) {  //第5行第5列有合并单元格,要取消\n                    luckysheet.cancelRangeMerge({range:"E5:F5"});\n                    luckysheet.setCellValue(4,4,"");\n                    luckysheet.setRangeMerge("all",{range:"B5:E5"});luckysheet.setRangeMerge("all",{range:"B5:E5"});\n                    luckysheet.setRangeMerge("all",{range:"F5:G5"});\n                    luckysheet.setCellValue(4,5,"服务名"); luckysheet.setCellFormat(4, 5,"bg",cellFormat.bg);luckysheet.setCellFormat(4, 5,"ht",cellFormat.ht);\n                }\n                mc = sheetdata[6][0]["mc"];\n                if(!isEmpty(mc) && mc.hasOwnProperty("rs")) {  //第7行有合并单元格\n                    luckysheet.cancelRangeMerge({range:"A7:A"+(7+mc["rs"]-1)});\n                    luckysheet.setCellValue(6,0,"参数");\n                    luckysheet.setCellValue(7,0,"输入参数");  luckysheet.setCellFormat(7, 0,"ht",cellFormat.ht);\n                    luckysheet.setRangeMerge("all",{range:"A8:A"+(7+mc["rs"]-1)});\n                }\n                mc = sheetdata[6][7]["mc"];\n                if(!isEmpty(mc) && mc.hasOwnProperty("cs")) {  //第7行有合并单元格\n                    luckysheet.cancelRangeMerge({range:"H7:I7"});\n                    luckysheet.setColumnWidth({7: 200});\n                }\n                luckysheet.setCellValue(6,4,"二级参数");\n                luckysheet.setCellValue(6,5,"必须");\n                luckysheet.setCellValue(6,6,"二级类型");\n                luckysheet.setCellValue(6,7,"字典");\n                luckysheet.setCellValue(6,8,"说明");  luckysheet.setCellFormat(6, 8,"bg",cellFormat.bg);\n                luckysheet.setColumnWidth({8: 400});\n                sheetdata = luckysheet.getSheetData();\n                for(var r=7;r<sheetdata.length;r++) {\n                    var col = sheetdata[r][6];\n                    if(!isEmpty(col) && col.hasOwnProperty("mc")) {\n                        mc = col["mc"];\n                        if (isNotEmpty(mc) && mc.hasOwnProperty("cs")) {  //第8行以后，第7列行有合并单元格，要取消调合并单元格\n                            luckysheet.cancelRangeMerge({range: "G" + (r + 1) + ":H" + (r + 1)});\n                            v = luckysheet.getCellValue(r, 6);\n                            if (isNotEmpty(v)) {\n                                luckysheet.setCellValue(r, 8, v);\n                                luckysheet.setCellValue(r, 6, "");\n                            }\n                        }\n                    }\n                    col = sheetdata[r][7];\n                    if(!isEmpty(col) && col.hasOwnProperty("mc")) {\n                        mc = col["mc"];\n                        if (isNotEmpty(mc) && mc.hasOwnProperty("cs")) {  //第8行以后，第7列行有合并单元格，要取消调合并单元格\n                            luckysheet.cancelRangeMerge({range: "H" + (r + 1) + ":I" + (r + 1)});\n                            v = luckysheet.getCellValue(r, 7);\n                            if (isNotEmpty(v)) {\n                                luckysheet.setCellValue(r, 8, v);\n                                luckysheet.setCellValue(r, 7, "");\n                            }\n                        }\n                    }\n                }\n                var timer = setTimeout(function () {\n                    $("#luckysheet-icon-save", container).attr("style", "color:#abb0b5");\n                    changeList = [];\n                    window.parent.postMessage({type: "changeApiStatus",status:false}, '/')\n                    loadingSheet = false;    //数据加载结束\n                    $("#apiDefineSheet").css("pointer-events","");  //激活表格页面\n                    clearTimeout(timer);\n                }, 200);\n            }});\n\n    }`
          if (treeObj.setting.callback.onClick.toString() == originFuncStr) {
            treeObj.setting.callback.onClick = async function selectApi(event, treeId, treeNode) {
              if (changeList.length > 0) {
                const result = await Swal.fire({
                  title: '提示',
                  html: '<span class="swal2-content">有修改还未保存，是否保存？</span>',
                  icon: 'warning',
                  showCloseButton: false,
                  showConfirmButton: true,
                  confirmButtonText: '确认',
                  showCancelButton: true,
                  cancelButtonText: '取消',
                })
                if (result.isConfirmed) {
                  saveApiDefine()
                  if (isChangeTree) {
                    saveApiTree('update', null, apiInfo, null, null, null)
                  }
                } else if (result.dismiss === Swal.DismissReason.cancel) {
                  changeList = []
                  window.parent.postMessage({ type: 'changeApiStatus', status: false }, '/')
                }
              }
              $('#luckysheet-icon-save', container).attr('style', 'color:#abb0b5')
              if (isNotEmpty(designApi)) {
                const result = await Swal.fire({
                  title: '提示',
                  html: `<span class="swal2-content">【${apiInfo.name}】设计说明还未保存，是否保存？</span>`,
                  icon: 'warning',
                  showCloseButton: false,
                  showConfirmButton: true,
                  confirmButtonText: '确认',
                  showCancelButton: true,
                  cancelButtonText: '取消',
                })
                if (result.isConfirmed) {
                  saveApiDesignDoc(editor.getHtml())
                } else if (result.dismiss === Swal.DismissReason.cancel) {
                  designApi = null
                  window.parent.postMessage({ type: 'changeDocStatus', status: isNotEmpty(designApi) }, '/')
                }
              }
              if (treeNode == undefined) return

              apiInfo = treeNode //zTree.getNodeByTId(treeNode.tId);
              if (treeNode != undefined && treeNode.isParent) {
                apiInfo['apiName'] = '接口定义'
                apiInfo['apiCode'] = 'apiDemo'
              }
              selectTab[0].click()
              loadingSheet = true //数据加载开始，允许所有单元格可编辑
              bCanModifyTemplate = false
              $('#apiDefineSheet').css('pointer-events', 'none') //冻结表格页面
              $('#luckysheet-input-box').css('top', -1000) //这个是为了避免上次公式框内容带到下个sheet的单元格中
              luckysheet.loadSheet(
                {
                  appId: appId,
                  appBranch: encodeURIComponent(appBranch),
                  apiCode: apiInfo.apiCode,
                  type: '1',
                },
                0,
                null,
                {
                  success: function (sheet) {
                    //修正旧格式
                    var cellFormat = { bg: '#F9CB9C', fc: '#000000', ht: 0, vt: 0 }
                    var bNewFormat =
                      luckysheet.getCellValue(4, 0) == '服务路径' || luckysheet.getCellValue(3, 0) == 'URL路径'
                        ? true
                        : false
                    if (luckysheet.getCellValue(3, 0) != 'URL路径') {
                      luckysheet.insertRow(3)
                      luckysheet.setCellValue(3, 0, 'URL路径')
                      luckysheet.setCellFormat(3, 0, 'bg', cellFormat.bg)
                      luckysheet.setCellFormat(3, 0, 'ht', cellFormat.ht)
                      luckysheet.setCellValue(3, bNewFormat ? 5 : 4, 'HTTP方法')
                      luckysheet.setCellFormat(3, bNewFormat ? 5 : 4, 'bg', cellFormat.bg)
                      luckysheet.setCellFormat(3, bNewFormat ? 5 : 4, 'ht', cellFormat.ht)
                      luckysheet.setCellValue(3, bNewFormat ? 7 : 6, 'POST')
                      luckysheet.setRangeMerge('horizontal', bNewFormat ? { range: 'B4:E4' } : { range: 'B4:D4' })
                      luckysheet.setRangeMerge('horizontal', bNewFormat ? { range: 'F4:G4' } : { range: 'E4:F4' })
                    }
                    if (luckysheet.getCellValue(4, 0) != '服务路径') {
                      luckysheet.insertRow(4)
                      luckysheet.setCellValue(4, 0, '服务路径')
                      luckysheet.setCellFormat(4, 0, 'bg', cellFormat.bg)
                      luckysheet.setCellFormat(4, 0, 'ht', cellFormat.ht)
                      luckysheet.setCellValue(4, bNewFormat ? 5 : 4, '服务名')
                      luckysheet.setCellFormat(4, bNewFormat ? 5 : 4, 'bg', cellFormat.bg)
                      luckysheet.setCellFormat(4, bNewFormat ? 5 : 4, 'ht', cellFormat.ht)
                      luckysheet.setCellValue(4, bNewFormat ? 7 : 6, '')
                      luckysheet.setRangeMerge('horizontal', { range: 'B5:D5' })
                      luckysheet.setRangeMerge('horizontal', { range: 'E5:F5' })
                    }
                    var sheetdata = luckysheet.getSheetData()
                    /*var mc = sheetdata[4][0]["mc"];
										if (!isEmpty(mc) && mc.hasOwnProperty("rs") && mc.rs > 1) {
											//第5行有合并单元格，要取消
											for (var i = 0; i < mc["rs"] - 1; i++) {
												luckysheet.deleteRow(5 + i, 5 + i);
											}
										}*/
                    var mc = sheetdata[5][0]['mc']
                    if (!isEmpty(mc) && mc.hasOwnProperty('rs') && mc.rs > 1) {
                      //第6行有合并单元格，要取消
                      for (var i = 0; i < mc['rs'] - 1; i++) {
                        luckysheet.deleteRow(6 + i, 6 + i)
                      }
                    }
                    if (!bNewFormat) {
                      var v = luckysheet.getCellValue(6, 4)
                      if (isEmpty(v) || !v.includes('参数')) {
                        luckysheet.insertColumn(4)
                        luckysheet.insertColumn(6)
                        luckysheet.setCellValue(6, 4, '二级参数')
                        luckysheet.setCellFormat(6, 4, 'bg', cellFormat.bg)
                        luckysheet.setCellValue(6, 6, '二级类型')
                        luckysheet.setCellFormat(6, 6, 'bg', cellFormat.bg)
                        //luckysheet.cancelRangeMerge("horizontal",{range:"B1:D5"});
                        luckysheet.setRangeMerge('horizontal', { range: 'B1:E5' })

                        luckysheet.deleteRange('left', { range: 'H1:H5' })
                        //luckysheet.cancelRangeMerge("horizontal",{range:"F1:H5"});
                        luckysheet.setRangeMerge('horizontal', { range: 'F1:G5' })

                        luckysheet.setColumnWidth({ 7: 400 })

                        var rows = luckysheet.getSheetData().length
                        //luckysheet.cancelRangeMerge({range: "F7:H" + rows});
                        v = luckysheet.getCellValue(6, 0)
                        /*if (isEmpty(v)) {
													luckysheet.deleteRow(6, 6);
													v = luckysheet.getCellValue(6, 0);
												}*/
                        if (isEmpty(v) || (!v.includes('入参') && !v.includes('参数'))) {
                          v = luckysheet.getCellValue(6, 1)
                          if (isEmpty(v) || (!v.includes('入参') && !v.includes('参数'))) {
                            bCanModifyTemplate = true
                            luckysheet.toolTip(
                              'info',
                              '错误',
                              '表格第7行异常，第7行不能跨行，且第7行第1列必须是标识为[输入参数]，请修正!'
                            )
                          }
                        }
                        v = luckysheet.getCellValue(6, 4)
                        if (isEmpty(v) || !v.includes('参数')) luckysheet.setCellValue(6, 4, '二级参数')
                        v = luckysheet.getCellValue(6, 6)
                        if (isEmpty(v) || !v.includes('类型')) luckysheet.setCellValue(6, 6, '二级类型')
                      }

                      luckysheet.setRangeMerge('horizontal', { range: 'B1:E1' })
                      luckysheet.setRangeMerge('horizontal', { range: 'B2:E2' })
                      luckysheet.setRangeMerge('horizontal', { range: 'B5:E5' })
                    }
                    // 开放范围默认
                    var v = luckysheet.getCellValue(2, 0)
                    if (v != '开放范围') {
                      luckysheet.setCellValue(2, 0, '开放范围')
                      v = luckysheet.getCellValue(2, 1)
                      luckysheet.setDataVerification(
                        {
                          type: 'dropdown',
                          value1: '内部,第三方,AI',
                          type2: true,
                          prohibitInput: true,
                        },
                        { range: 'B3:B3' }
                      )
                      luckysheet.setCellValue(2, 1, v == 'Y' ? '第三方' : '内部')
                    } else {
                      // 默认添加开放范围验证
                      luckysheet.setDataVerification(
                        {
                          type: 'dropdown',
                          value1: '内部,第三方,AI',
                          type2: true,
                          prohibitInput: true,
                        },
                        { range: 'B3:B3' }
                      )
                    }
                    // 接口状态
                    v = luckysheet.getCellValue(2, 3)
                    if (isEmpty(v)) {
                      if (sheetdata[2][1].hasOwnProperty('mc')) {
                        luckysheet.cancelRangeMerge({ range: 'B3:E3' })
                      }
                      luckysheet.setRangeMerge('all', { range: 'B3:C3' })
                      luckysheet.setCellValue(2, 3, '状态')
                      luckysheet.setCellFormat(2, 3, 'bg', cellFormat.bg)
                      luckysheet.setCellFormat(2, 3, 'fc', cellFormat.fc)
                      luckysheet.setCellFormat(2, 3, 'ht', cellFormat.ht)
                      //luckysheet.setDataVerification({ "type": "dropdown", "value1": "正常,草稿,作废",   "prohibitInput": true   }, {range:"E3:E3"});
                      v = luckysheet.getCellValue(1, 1)
                      var status = '正常'
                      if (!isEmpty(v)) {
                        if (v.startsWith('（')) {
                          status = v.substr(1, v.indexOf('）') - 1)
                          luckysheet.setCellValue(1, 1, v.replace('（' + status + '）', ''))
                        }
                      }
                      apiInfo['status'] = status
                      luckysheet.setCellValue(2, 4, status)
                    }
                    // 接口类型
                    v = luckysheet.getCellValue(3, 3)
                    if (isEmpty(v)) {
                      if (sheetdata[3][1].hasOwnProperty('mc')) {
                        luckysheet.cancelRangeMerge({ range: 'B4:E4' })
                      }
                      luckysheet.setRangeMerge('all', { range: 'B4:C4' })
                      luckysheet.setCellValue(3, 3, '接口类型')
                      luckysheet.setCellFormat(3, 3, 'bg', cellFormat.bg)
                      luckysheet.setCellFormat(3, 3, 'ht', cellFormat.ht)
                      luckysheet.setDataVerification(
                        {
                          type: 'dropdown',
                          value1: '标准接口,编织接口',
                          prohibitInput: true,
                        },
                        { range: 'E4:E4' }
                      )
                      luckysheet.setCellValue(3, 4, '标准接口')
                    } else {
                      luckysheet.setDataVerification(
                        {
                          type: 'dropdown',
                          value1: '标准接口,编织接口',
                          prohibitInput: true,
                        },
                        { range: 'E4:E4' }
                      )
                    }
                    sheetdata = luckysheet.getSheetData()
                    var mc = sheetdata[4][4]['mc']
                    if (!isEmpty(mc) && mc.hasOwnProperty('cs')) {
                      //第5行第5列有合并单元格,要取消
                      luckysheet.cancelRangeMerge({ range: 'E5:F5' })
                      luckysheet.setCellValue(4, 4, '')
                      luckysheet.setRangeMerge('all', { range: 'B5:E5' })
                      luckysheet.setRangeMerge('all', { range: 'B5:E5' })
                      luckysheet.setRangeMerge('all', { range: 'F5:G5' })
                      luckysheet.setCellValue(4, 5, '服务名')
                      luckysheet.setCellFormat(4, 5, 'bg', cellFormat.bg)
                      luckysheet.setCellFormat(4, 5, 'ht', cellFormat.ht)
                    }
                    mc = sheetdata[6][0]['mc']
                    if (!isEmpty(mc) && mc.hasOwnProperty('rs')) {
                      //第7行有合并单元格
                      luckysheet.cancelRangeMerge({ range: 'A7:A' + (7 + mc['rs'] - 1) })
                      luckysheet.setCellValue(6, 0, '参数')
                      luckysheet.setCellValue(7, 0, '输入参数')
                      luckysheet.setCellFormat(7, 0, 'ht', cellFormat.ht)
                      luckysheet.setRangeMerge('all', {
                        range: 'A8:A' + (7 + mc['rs'] - 1),
                      })
                    }
                    mc = sheetdata[6][7]['mc']
                    if (!isEmpty(mc) && mc.hasOwnProperty('cs')) {
                      //第7行有合并单元格
                      luckysheet.cancelRangeMerge({ range: 'H7:I7' })
                      luckysheet.setColumnWidth({ 7: 200 })
                    }
                    luckysheet.setCellValue(6, 4, '二级参数')
                    luckysheet.setCellValue(6, 5, '必须')
                    luckysheet.setCellValue(6, 6, '二级类型')
                    luckysheet.setCellValue(6, 7, '字典')
                    luckysheet.setCellValue(6, 8, '说明')
                    luckysheet.setCellFormat(6, 8, 'bg', cellFormat.bg)
                    luckysheet.setColumnWidth({ 8: 400 })
                    luckysheet.scroll({ scrollLeft: 0, scrollTop: 0 })
                    sheetdata = luckysheet.getSheetData()
                    for (var r = 7; r < sheetdata.length; r++) {
                      var col = sheetdata[r][6]
                      if (!isEmpty(col) && col.hasOwnProperty('mc')) {
                        mc = col['mc']
                        if (isNotEmpty(mc) && mc.hasOwnProperty('cs')) {
                          //第8行以后，第7列行有合并单元格，要取消调合并单元格
                          luckysheet.cancelRangeMerge({
                            range: 'G' + (r + 1) + ':H' + (r + 1),
                          })
                          v = luckysheet.getCellValue(r, 6)
                          if (isNotEmpty(v)) {
                            luckysheet.setCellValue(r, 8, v)
                            luckysheet.setCellValue(r, 6, '')
                          }
                        }
                      }
                      col = sheetdata[r][7]
                      if (!isEmpty(col) && col.hasOwnProperty('mc')) {
                        mc = col['mc']
                        if (isNotEmpty(mc) && mc.hasOwnProperty('cs')) {
                          //第8行以后，第7列行有合并单元格，要取消调合并单元格
                          luckysheet.cancelRangeMerge({
                            range: 'H' + (r + 1) + ':I' + (r + 1),
                          })
                          v = luckysheet.getCellValue(r, 7)
                          if (isNotEmpty(v)) {
                            luckysheet.setCellValue(r, 8, v)
                            luckysheet.setCellValue(r, 7, '')
                          }
                        }
                      }
                    }
                    var timer = setTimeout(function () {
                      $('#luckysheet-icon-save', container).attr('style', 'color:#abb0b5')
                      changeList = []
                      window.parent.postMessage({ type: 'changeApiStatus', status: false }, '/')
                      loadingSheet = false //数据加载结束
                      $('#apiDefineSheet').css('pointer-events', '') //激活表格页面
                      clearTimeout(timer)
                    }, 200)
                  },
                }
              )
            }
          } else if (!treeObj.setting.callback.onClick.toString().includes('// 默认添加开放范围验证')) {
            createAlert('函数 zTree.setting.callback.onClick 版本有变动，请更新脚本代码', 'error')
          }
        } else {
          createAlert('函数 zTree.setting.callback.onClick 还未加载', 'warning')
        }

        return treeObj
      }
    }
  })




  GM_addStyle(`
		/* 产品接口文档 接口图标修正 */
		.ztree li span.button.ico_docu {
				background-position: -110px -31px !important;
		}
		.ztree li span.button {
				height: 14px !important;
		}
		.ztree li span.button.ico_open {
				background-position: -110px -15px !important;
		}
		.ztree li span.button.add {
				background-position: -144px 1px !important;
		}
		.ztree li span.button.edit {
				background-position: -110px -47px !important;
		}
		/* 产品接口文档树 优化样式 */
		.ztree li a.curSelectedNode {
				background-color: bisque !important;
				height: 16px !important;
				border-radius: 3px;
		}
		.ztree li a {
				padding: 2px 0px 2px 0px !important;
				height: 17px !important;
				font-size: 13px !important;
		}
		.ztree li a:hover {
				background-color: bisque !important;
				padding: 2px 0px 2px 0px !important;
				font-size: 13px !important;
				border-radius: 3px;
		}
		#apiList{
			height: calc(100vh - 22px) !important;
			padding-top: 10px;
		}
		.ztree li a.tmpTargetNode_inner {
			background-color: #70B5FC !important;
			color:white; height:16px !important;
			border:1px #4191E2 solid !important;
			border-radius: 3px;
		}
		.ztree li a.curSelectedNode_Edit input.rename{
			width: fit-content ;
			font-size: 13px;
		}
		ul#apiTree {
			height: 93% !important;
		}
`)
}

function perfAmsCodeEditor() {


  elmGetter.each(".sidebar", document, (sidebar) => {

    /**
     * 处理单个 .siderbar 元素，进行去重和排序
     * @param {HTMLElement} sidebar - 要处理的侧边栏元素
     */
    function processSidebar(sidebar) {
        // 获取所有 .tab 元素
        const tabs = Array.from(sidebar.querySelectorAll(".tab"));

				function prioritySort(arr, priorityList = ["codeSetting", "addTemplate"]) {
					return arr.sort((x, y) => {
						const xPriority = priorityList.indexOf(x);
						const yPriority = priorityList.indexOf(y);

						if (xPriority !== -1 && yPriority !== -1) return xPriority - yPriority; // 按列表顺序排序
						if (xPriority !== -1) return -1; // x 是目标，排前面
						if (yPriority !== -1) return 1; // y 是目标，排前面
						return x.localeCompare(y); // 其他按字母排序
					});
				}


				// 示例


        // 使用 Set 去重
        const seen = Array.from(new Set(tabs.map(tab => $(tab).attr('targetName'))));
				prioritySort(seen);

        // 分类排序：优先级为 targetname → addTemplate → 其他
        const sortedTabs = seen.map((v) =>
          tabs.find(
            (tab) =>
              $(tab).attr('targetName') === v &&
              (['codeSetting', 'addTemplate'].includes($(tab).attr('targetName'))
                ? $(tab).attr('targetName') !== $(tab).text()
                : true)
          )
        )

        // 如果有变化，则替换子元素
        if (sortedTabs.length !== tabs.length) {
            sidebar.replaceChildren(...sortedTabs);
            // 可选：记录更新时间或其他操作
            console.log(`左侧模版更新`);
        }

        // 应用样式
        GM_addStyle(`
            .sidebar {
                overflow: auto;
            }
        `);
    }

    // 立即处理现有的 .siderbar 元素
    processSidebar(sidebar);

		// 创建一个 MutationObserver 实例
		const observer = new MutationObserver(mutations => {
				// 遍历所有变化
				mutations.forEach(mutation => {
						// 如果有子节点被添加或移除，则重新处理该侧边栏
						if (mutation.type === 'childList') {
								processSidebar(sidebar);
						}
				});
		});

		// 配置观察选项：监听子节点的添加和移除
		const config = { childList: true };

		// 开始观察该侧边栏
		observer.observe(sidebar, config);

  });
	GM_addStyle(`.sidebar{overflow:auto;}`);

}


// 补充接口文件夹的接口数量统计，忽略新加未维护内容的节点
function fillAllNodeNameWithChildCount() {
  /*var apiTree = sheetIframe.contentWindow.zTree
  var apiNodes = apiTree.getNodes()
  if (apiTree) {
    var treeDatas = apiTree.transformTozTreeNodes(apiNodes)
    function countChild(children) {
      var apiCount = 0
      var apiNode = children.filter((v) => v.isParent == false && v.apiCode != 'apiDemo')
      apiCount += apiNode.length
      var parentNodes = children.filter((v) => v.isParent == true && Array.isArray(v.children) && v.children.length > 0)
      parentNodes.forEach((p) => {
        if (Array.isArray(p.children) && p.children.length > 0) {
          apiCount += countChild(p.children)
        }
      })
      return apiCount
    }
    function fillNameWithChildCount(parentNode) {
      var apiCount = 0
      // 拼接新的字符串
      const newTid = parentNode.tId
      var nameNode = document.querySelector(`#${newTid}>a>span.node_name`)
      if (!nameNode) return
      //const pNode = zTree.getNodeByParam("id", parentNode.id, null);
      //var nameNode = zTree.getNodeByParam("id", newTid, null);
      const { id, children = [] } = parentNode
      if (parentNode.isParent == true && Array.isArray(children) && children.length > 0) {
        apiCount = countChild(children)
        nameNode.innerText = parentNode.name + `(${apiCount})`
        parentNode.children.forEach((p) => {
          fillNameWithChildCount(p)
        })
      } else if (parentNode.isParent == true && children.length == 0) {
        nameNode.innerText = parentNode.name + `(0)`
      } else {
        // 普通节点
      }
    }
    treeDatas.forEach((p) => {
      fillNameWithChildCount(p)
    })
  }
  // posiToCurrSelectedNode('apiTree')*/
}

// 数据模型树，增加工具栏、图标样式修正
function perfDataModelDocTree() {
  // 接口树增强，增加扩展按钮
  elmGetter.each('#modelList', document, (modelList) => {
    sheetIframe = window.frameElement

    var toolBarDiv = createDivByHtml(`<div id='modelListToolbar' style='margin-bottom:-5px' />`)
    modelList.insertBefore(toolBarDiv, modelList.firstChild)

    // 折叠所有
    var btnCollApseAll = createDivByHtml(
      `<button type="button" id="btn_collapseAll" style="font-size: 12px">折叠</button>`
    )
    btnCollApseAll.addEventListener('click', function () {
      sheetIframe.contentWindow.postMessage({ type: 'collapseAll' }, '/')
    })

    toolBarDiv.appendChild(btnCollApseAll)

    // 展开一级
    var btnExpandFirst = createDivByHtml(
      `<button type="button" id="btn_expandAll" style="font-size: 12px">展开一级</button>`
    )
    btnExpandFirst.addEventListener('click', function () {
      // 关闭二级
      document
        .querySelectorAll('#modelTree>li>ul>li>span.center_open, #modelTree>li>ul>li>span.bottom_open')
        .forEach((v) => v.click())
      // 展开一级
      document
        .querySelectorAll(
          '#modelTree>li>span.roots_close, #modelTree>li>span.center_close, #modelTree>li>span.bottom_close'
        )
        .forEach((v) => v.click())
    })

    toolBarDiv.appendChild(btnExpandFirst)

    // 展开全部
    var btnExpandAll = createDivByHtml(
      `<button type="button" id="btn_expandAll" style="font-size: 12px">展开全部</button>`
    )
    btnExpandAll.addEventListener('click', function () {
      zTree.expandAll(true)
    })

    toolBarDiv.appendChild(btnExpandAll)

    // 刷新
    var btnRefresh = createDivByHtml(`<button type="button" id="btn_refresh" style="font-size: 12px">刷新</button>`)
    btnRefresh.addEventListener('click', function () {
      zTree.expandAll(true)
      count = 1
      refreshTree(sheetIframe.contentWindow.appId, sheetIframe.contentWindow.appBranch)
    })

    toolBarDiv.appendChild(btnRefresh)

    // 定位
    var btnPosiDiv = createDivByHtml(
      `<button type="button" disabled id="btn_posi" style="font-size: 12px">定位</button>`
    )
    btnPosiDiv.addEventListener('click', function () {
      if (modelInfo && modelInfo.id) {
        posiToCurrSelectedNode(modelInfo.id)
      }
      /*
      posiToCurrSelectedNode('modelTree')*/
    })

    toolBarDiv.appendChild(btnPosiDiv)


  });

  // 重写刷新接口列表函数，刷新后重新加载文件夹子接口数量
  elmGetter.each('#modelTree', document, (modelTree) => {
    // 定义属性变化的回调函数
    var observerCallback = function (mutationsList) {
      for (let mutation of mutationsList) {
        if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
          var btnPosiDiv = document.querySelector('#btn_posi')
          if (getCurrApiNodeTop('modelTree').dom) {
            btnPosiDiv.disabled = false
          } else {
            btnPosiDiv.disabled = true
          }
        }
      }
    }
    // 创建一个观察者实例并配置观察选项
    var observer = new MutationObserver(observerCallback)
    var observerConfig = {
      attributes: true,
      attributeFilter: ['class'], // 仅监控class属性
      subtree: true,
    }
    // 开始观察ul元素及其子元素的class属性变动
    observer.observe(modelTree, observerConfig)

    sheetIframe.contentWindow.onload = function () {
      // 刷新树时计算树数量
      var _1 = refreshTree
      console.log('refreshTree')

      refreshTree = async function (arg1, arg2) {
        _1(arg1, arg2)
        zTree = sheetIframe.contentWindow.zTree

        // 初始化全量表
/*
        // 使用函数并打印结果
        var responseJson = await refreshModelData(arg1, arg2)
        sessionStorage.setItem('modelDataSource', JSON.stringify(responseJson))
        var responseJson2 = await refreshDataType(arg1, arg2)
        sessionStorage.setItem('modelDataType', JSON.stringify(responseJson2))

        console.log('All Model DataSource fetched')
*/
        // zTree.expandAll(true)
        fillAllNodeNameWithChildCount()
        if (count == 1) {
          // zTree.expandAll(false)
          count++
        }
      }

      // 树变动后，自动跳到对应节点
      var _2 = saveModelTree
      if(saveModelTree){
        var originFuncStr = `function saveModelTree(event, treeId, treeNode, targetNode, moveType,isCopy) {\n        refreshTree(appId,appBranch);\n        var node;\n        if(treeNode) {\n            //前面refreshTree重新构造了tree，必须重新获取一次\n            node =  zTree.getNodeByParam("id",treeNode.id, null);\n            if(treeNode.env!=undefined){\n                node.env  = treeNode.env;\n            }\n        }\n        if(targetNode) {\n            //前面refreshTree重新构造了tree，必须重新获取一次\n            targetNode = zTree.getNodeByParam("id", targetNode.id, null);\n            //console.log(event,treeNode,node,targetNode, moveType,isCopy)\n        }else{\n            targetNode = zTree.getNodeByParam("id", treeNode.pId, null);\n        }\n        if(event=="add"){\n            if(treeNode.modelCode) {\n                node = zTree.getNodeByParam("modelCode", treeNode.modelCode, null);\n            }\n            if(node==null){\n                zTree.addNodes(targetNode, treeNode);\n            }else{\n                delete node.isDelete;\n                zTree.updateNode(node);\n            }\n        }else if(event=="delete") {\n            targetNode = zTree.getNodeByParam("id", node.pId, null);    //这个操作让删除节点后，展开父节点\n            zTree.removeNode(node,false)\n            /*\n            if(node.isParent){\n                zTree.removeNode(node,false)\n            }else {\n                if(node.isDelete){\n                    zTree.removeNode(node,false)\n                }else {\n                    node.isDelete = true;\n                    zTree.updateNode(node);\n                }\n            }*/\n        }else if(event=="update"){\n            if(treeNode.isParent) {\n                node.name = treeNode.name;\n            }else{\n                node.name = treeNode.modelName + "/" + treeNode.modelCode;\n                node.modelCode = treeNode.modelCode;\n                node.modelName = treeNode.modelName;\n                node.isOpen = treeNode.isOpen;\n                node.version = treeNode.version;\n            }\n            zTree.updateNode(node);\n        }else if(event=="move") {\n            if(targetNode) {\n                targetNode = zTree.getNodeByTId(targetNode.tId);\n            }else if(!node.isParent){\n                return node;\n            }\n            var dragNode = zTree.getNodeByTId(node.tId);\n            if (targetNode) {\n                zTree.moveNode(targetNode, dragNode, moveType, false);\n            } else if (dragNode.isParent) {\n                zTree.moveNode(null, dragNode, "next", false);\n            }\n        }else if(event=="release"){\n            zTree.getNodesByParam("isParent", false, null).forEach(function(node) {\n                zTree.getNodeByTId(node.tId).version = "release";\n            })\n        }\n        function simplifyTree(treeNodes) {\n            treeNodes.forEach(function (node, pIdx, array) {\n                delete (treeNodes[pIdx]).zAsync;\n                delete (treeNodes[pIdx]).check_Focus;\n                delete (treeNodes[pIdx]).checked;\n                delete (treeNodes[pIdx]).editNameFlag;\n                delete (treeNodes[pIdx]).nocheck;\n                delete (treeNodes[pIdx]).chkDisabled;\n                delete (treeNodes[pIdx]).isHover;\n                delete (treeNodes[pIdx]).isAjaxing;\n                delete (treeNodes[pIdx]).checkedOld;\n                delete (treeNodes[pIdx]).isHidden;\n                delete (treeNodes[pIdx]).halfCheck;\n                delete (treeNodes[pIdx]).check_Child_State;\n                delete (treeNodes[pIdx]).open;\n                delete (treeNodes[pIdx]).isFirstNode;\n                delete (treeNodes[pIdx]).isLastNode;\n                delete (treeNodes[pIdx]).parentTId;\n                delete (treeNodes[pIdx]).tId; //tId在每次刷新tree后都会自动重新生成\n                if (treeNodes[pIdx]["children"] != undefined && treeNodes[pIdx]["children"].length > 0) {\n                    simplifyTree(treeNodes[pIdx]["children"]);\n                }\n            });\n            return treeNodes;\n        }\n        zNodes = simplifyTree(zTree.getNodes());  //剔除多余信息\n\n        $.ajax({\n            url: "dataModelService.jsp?MOD=saveModelList",\n            type: "POST",\n            data: {appId: appId,appBranch:encodeURIComponent(appBranch), modelList: encodeURIComponent(JSON.stringify(zNodes))},\n            async:false,\n            dataType: "JSON",\n            success: function (ret) {\n                if (ret && ret['CODE'] && parseInt(ret['CODE']) > 0) {\n                    $("#luckysheet_info_detail_save").text("已保存");\n                } else {\n                    alert("保存模型定义出错," + ret['NOTE']);\n                    return null;\n                }\n            }, error: function (text, msg, e) {\n                alert("会话已过期!");\n                return null;\n            }\n        });\n        isChangeTree = false;\n        refreshTree(appId,appBranch);\n        if(targetNode) {\n            //前面refreshTree重新构造了tree，必须重新获取一次\n            targetNode = zTree.getNodeByParam("id", targetNode.id, null);\n            if(!targetNode.open){\n                zTree.expandNode(targetNode, true, false, true);\n            }\n        }\n        if(["add","update","move"].includes(event)) {\n            node = zTree.getNodeByParam("id", treeNode.id, null);\n        }\n        return node;\n\n    }`;
        if (originFuncStr === saveModelTree.toString()) {
          saveModelTree = function saveModelTree(event, treeId, treeNode, targetNode, moveType, isCopy) {
            var checkNodes = zTree.getCheckedNodes(true);//所有选中节点
            var checkChilds = checkNodes.filter((v) => !v.isParent);//所有选中子节点
            var singleParentAllSec = checkNodes.filter((v) => v.isParent && v?.check_Child_State == 2); // 是否选中了单个目录下的所有节点
            refreshTree(appId, appBranch);

            function isParent(targetNode, node) {
              while (node) {
                if (node.id === targetNode.id) {
                  return true
                }
                node = node.getParentNode()
              }
              return false
            }
            var node
            if (treeNode) {
              //前面refreshTree重新构造了tree，必须重新获取一次
              node = zTree.getNodeByParam('id', treeNode.id, null)
              if (treeNode.env != undefined) {
                node.env = treeNode.env
              }
            }
            if (targetNode) {
              //前面refreshTree重新构造了tree，必须重新获取一次
              targetNode = zTree.getNodeByParam('id', targetNode.id, null)
              //console.log(event,treeNode,node,targetNode, moveType,isCopy)
            } else {
              targetNode = zTree.getNodeByParam('id', treeNode.pId, null)
            }
            // 开头添加处理，如果移动多个节点

						// 获取所有子节点的父节点ID,由于代码运行到这里，前端的node已经有一个节点移动了，父目录会变成新目录，故需要筛选在选中nodes范围内的父节点
						const parentIds = new Set(checkNodes.filter((v) => !v.isParent).map(child => child.pId).filter(v=>checkNodes.some(x=>x.id === v)));
						// 如果子节点来自多个不同的父节点，则不允许移动
						if ( checkChilds.length > 1 && parentIds.size > 1) {
								createAlert("不支持跨目录移动多个接口", "error", 1500);
								return null;
						}
            // 如果选中了单个目录下的所有节点，则改为移动此目录
						if (
							singleParentAllSec.length == 1 &&
							checkNodes.filter((v) => v.isParent).length == 1 &&
							node.id != targetNode.id && parentIds
						) {
							createAlert("如果要移动整个目录节点，请选中目录进行拖拽", "warn");
							// return null;
						}
            // 判断选中的节点数量是否超过一个，如果超过一个，则批量移动（仅移动子节点）, 这是不管移动的是哪个节点，都会仅处理选中的节点
            if (checkChilds.length > 1 && event == 'move') {
              // 移动多个节点
              if (targetNode) {
                targetNode = zTree.getNodeByTId(targetNode.tId)
              } else if (!node.isParent) {
                return node
              }
              // 移动节点
              if(moveType === 'inner' || moveType === 'prev'){
                treeNode = checkChilds[0];
                // 顺序执行
                for (var i =0;i< checkChilds.length; i++) {
                  var eachNode = zTree.getNodeByParam('id', checkChilds[i].id, null)
                  // 检查是否尝试将节点移动到自身或自己的子节点下
                  zTree.moveNode(targetNode, eachNode, moveType)
                }
              }else{
                // 倒序执行
                treeNode = checkChilds[checkChilds.length-1];
                for (var i = checkChilds.length-1;i>=0; i--) {
                  var eachNode = zTree.getNodeByParam('id', checkChilds[i].id, null)
                  // 检查是否尝试将节点移动到自身或自己的子节点下
                  if (eachNode.id === targetNode.id || isParent(targetNode, eachNode)) {
                    createAlert('不能将节点移动到自身或自己的子节点下！','error',1500)
                    continue
                  }
                  zTree.moveNode(targetNode, eachNode, moveType)
                }
              }

            } else {
              var trueMoveType = moveType
              if (moveType === 'nodeAdd') trueMoveType = null
              else if (event === 'delete') {
                refreshTree(appId, appBranch)
                var node = zTree.getNodeByParam('id', treeNode.id, null)
                if (targetNode) {
                  //前面refreshTree重新构造了tree，必须重新获取一次
                  targetNode = zTree.getNodeByParam('id', targetNode.id, null)
                }
                //这个操作让删除节点后，展开父节点，选择到删除节点的上一个节点，如果没有则展示到父节点
                if (node.getPreNode()) {
                  targetNode = node.getPreNode()
                } else if (node.getParentNode()) {
                  targetNode = node.getParentNode()
                }
              }
              // 原始处理
              if (event == 'add') {
                if (treeNode.modelCode) {
                  node = zTree.getNodeByParam('modelCode', treeNode.modelCode, null)
                }
                if (node == null) {
                  zTree.addNodes(targetNode, treeNode)
                } else {
                  delete node.isDelete
                  zTree.updateNode(node)
                }
              } else if (event == 'delete') {
                targetNode = zTree.getNodeByParam('id', node.pId, null) //这个操作让删除节点后，展开父节点
                zTree.removeNode(node, false)
              } else if (event == 'update') {
                if (treeNode.isParent) {
                  node.name = treeNode.name
                } else {
                  node.name = treeNode.modelName + '/' + treeNode.modelCode
                  node.modelCode = treeNode.modelCode
                  node.modelName = treeNode.modelName
                  node.isOpen = treeNode.isOpen
                  node.version = treeNode.version
                }
                zTree.updateNode(node)
              } else if (event == 'move') {
                if (targetNode) {
                  targetNode = zTree.getNodeByTId(targetNode.tId)
                } else if (!node.isParent) {
                  return node
                }
                var dragNode = zTree.getNodeByTId(node.tId)
                if (targetNode) {
                  zTree.moveNode(targetNode, dragNode, moveType, false)
                } else if (dragNode.isParent) {
                  zTree.moveNode(null, dragNode, 'next', false)
                }
              } else if (event == 'release') {
                zTree.getNodesByParam('isParent', false, null).forEach(function (node) {
                  zTree.getNodeByTId(node.tId).version = 'release'
                })
              }
            }
            function simplifyTree(treeNodes) {
              treeNodes.forEach(function (node, pIdx, array) {
                delete treeNodes[pIdx].zAsync
                delete treeNodes[pIdx].check_Focus
                delete treeNodes[pIdx].checked
                delete treeNodes[pIdx].editNameFlag
                delete treeNodes[pIdx].nocheck
                delete treeNodes[pIdx].chkDisabled
                delete treeNodes[pIdx].isHover
                delete treeNodes[pIdx].isAjaxing
                delete treeNodes[pIdx].checkedOld
                delete treeNodes[pIdx].isHidden
                delete treeNodes[pIdx].halfCheck
                delete treeNodes[pIdx].check_Child_State
                delete treeNodes[pIdx].open
                delete treeNodes[pIdx].isFirstNode
                delete treeNodes[pIdx].isLastNode
                delete treeNodes[pIdx].parentTId
                delete treeNodes[pIdx].tId //tId在每次刷新tree后都会自动重新生成
                if (treeNodes[pIdx]['children'] != undefined && treeNodes[pIdx]['children'].length > 0) {
                  simplifyTree(treeNodes[pIdx]['children'])
                }
              })
              return treeNodes
            }
            zNodes = simplifyTree(zTree.getNodes()) //剔除多余信息

            $.ajax({
              url: 'dataModelService.jsp?MOD=saveModelList',
              type: 'POST',
              data: {
                appId: appId,
                appBranch: encodeURIComponent(appBranch),
                modelList: encodeURIComponent(JSON.stringify(zNodes)),
              },
              async: false,
              dataType: 'JSON',
              success: function (ret) {
                if (ret && ret['CODE'] && parseInt(ret['CODE']) > 0) {
                  $('#luckysheet_info_detail_save').text('已保存')
                } else {
                  alert('保存模型定义出错,' + ret['NOTE'])
                  return null
                }
              },
              error: function (text, msg, e) {
                alert('会话已过期!')
                return null
              },
            })
            isChangeTree = false
            refreshTree(appId, appBranch)
            if (targetNode) {
              //前面refreshTree重新构造了tree，必须重新获取一次
              targetNode = zTree.getNodeByParam('id', targetNode.id, null)
              if (!targetNode.open) {
                zTree.expandNode(targetNode, true, false, true)
              }
            }
            if (['add', 'update', 'move'].includes(event)) {
              node = zTree.getNodeByParam('id', treeNode.id, null)
            }

            // 结尾添加处理
            if (node && event !== 'delete') {
              // 待ztree展开到指定节点后，处理滚动条到对应位置
              setTimeout(() => {
                posiToCurrSelectedNode(node.id)
              }, 200)
            } else if (event == 'delete') {
              if (targetNode) {
                setTimeout(() => {
                  posiToCurrSelectedNode(targetNode.id)
                }, 200)
              }
            }
            return node
          }
        }else if (!checkDataValidity.toString().includes('开头添加处理，如果移动多个节点')) {
          createAlert('模型表格方法 saveModelTree 版本有变动，请更新脚本代码', 'error')
          return
        }
      }


      // 优化数据校验报错
      if (checkDataValidity) {
        var originFuncStr =
          'function checkDataValidity(index,range,data){\n        if(isEmpty(index) || isEmpty(range)){\n            return false;\n        }\n        try {\n            var status = true;\n            var r = (typeof range.row)=="object"?range.row[0]:range.row;\n            var end_r = (typeof range.row)=="object"?range.row[1]:range.row;\n            var c = (typeof range.column)=="object"?range.column[0]:range.column;\n            var end_c = (typeof range.column)=="object"?range.column[1]:range.column;\n            if (index == "columnsSheet") {\n                if (r < 2 && c == 1) { //模型代码和模型名称\n                    var value = (typeof data)=="object"?data[0][0]:data;   //提取第一个元素的值\n                    if (isEmpty(value)) {\n                        alert("功能码或功能名称不能为空");\n                        return false;\n                    }\n                    if (r==0 && !validKey.test(value)) {\n                        luckysheet.toolTip("info", "错误", "模型代码" + value + "不能包含特殊字符和汉字，不能以数字开头");\n                        return false;\n                    } else {\n                        function filter(node) {\n                            return ((node.modelCode+"").toLowerCase() == (value+"").toLowerCase() && node.tId != modelInfo.tId);\n                        }\n\n                        if (zTree.getNodesByFilter(filter, true)) {\n                            //alert("模型重名");\n                            luckysheet.toolTip("info", "错误", "模型重名");\n                            // luckysheet.setCellValue(0, 1,modelInfo.modelCode,false);\n                            return false;\n                        }\n                    }\n                } /*else if (r > 3 && c < 2) {\n                    var ret = luckysheet.find(value, {isWholeWord: true, range: {row: [4, 10000], column: [0, 0]}})\n                    if (ret.length > 0) {\n                        luckysheet.toolTip("info", "错误", "字段重复");\n                        return false;\n                    }\n                }*/\n                /*if (r > 3 && c == 0 && (typeof data)=="object")  {\n                    data.forEach(function (rv, r) {\n                        rv.forEach(function (cv, c) {\n                            if (c == 0 && !validKey.test(cv)) {\n                                status = false;\n                                luckysheet.toolTip("info", "错误", "字段代码不能包含特殊字符和汉字：" + cv);\n                                return;\n                            }\n                        });\n                    });\n                    if (status == false) {\n                        return false;\n                    }\n                }*/\n            }\n        }catch (e){\n            luckysheet.toolTip("info", "错误", "数据合法性判断异常:" + e);\n            return false;\n        }\n        return true;\n    }'
        if (checkDataValidity.toString() == originFuncStr) {
          checkDataValidity = function checkDataValidity(index, range, data) {
            if (isEmpty(index) || isEmpty(range)) {
              return false
            }
            try {
              var status = true
              var r = typeof range.row == 'object' ? range.row[0] : range.row
              var end_r = typeof range.row == 'object' ? range.row[1] : range.row
              var c = typeof range.column == 'object' ? range.column[0] : range.column
              var end_c = typeof range.column == 'object' ? range.column[1] : range.column
              if (index == 'columnsSheet') {
                if (r < 2 && c == 1) {
                  //模型代码和模型名称
                  var value
                  if (Array.isArray(data) && typeof data === 'object') {
                    value = data[0][0]
                  } else {
                    value = data
                  }
                  if (isEmpty(value)) {
                    createAlert('模型名不能为空', 'error')
                    return false
                  }
                  if (r == 0 && !validKey.test(value)) {
                    createAlert('模型代码' + value + '不能包含特殊字符和汉字，不能以数字开头', 'error')
                    return false
                  } else {
                    function filter(node) {
                      return (
                        (node.modelCode + '').toLowerCase() == (value + '').toLowerCase() && node.tId != modelInfo.tId
                      )
                    }
                    if (zTree.getNodesByFilter(filter, true)) {
                      createAlert('模型重名', error)
                      return false
                    }
                  }
                }
              }
            } catch (e) {
              createAlert('数据合法性判断异常:' + e, 'error')
              return false
            }
            return true
          }
        } else if (checkDataValidity.toString().includes('var v = (typeof data)=="object"?data[0][0]:data;')) {
          createAlert('模型表格方法 checkDataValidity 版本有变动，请更新脚本代码', 'error')
          return
        }

        var _3 = checkDataValidity
        checkDataValidity = function (index, range, data) {
          ls = sheetIframe.contentWindow.luckysheet

          var r = typeof range.row == 'object' ? range.row[0] : range.row
          var c = typeof range.column == 'object' ? range.column[0] : range.column
          if (r < 2 && c == 1 && !Array.isArray(data) && typeof data === 'object') {
            data = data.v
          } else if (!Array.isArray(data) && typeof data === 'object') {
            data = [data]
          }
          // 限制模型名、字段名长度
          if ((r == 0 && c == 1) || (r >= 4 && c == 0)) {
            const codeCell = ls.getRangeValue({ range: { row: [r, r], column: [c, c] } })

            var code = ''

            codeCell.forEach((row) => {
              // 遍历行中的每个单元格
              row.forEach((cell) => {
                if (cell && typeof cell.v === 'string') {
                  code = cell.v
                }
              })
            })

            if (r == 0 && code === data && code.length > 30) {
              createAlert(`表名[${code}]长度过长:${code.length}，请调整`, 'error')
            } else if (r >= 4 && data.length > 30) {
              createAlert(`字段名[${data}]长度过长:${data.length}，请调整`, 'error')
            }
          }
          _3(index, range, data)
        }
      }

      var _4 = luckysheet.create
      luckysheet.create = function (setting) {
        if (setting?.hook?.rangePasteBefore) {
          setting.hook.rangePasteBefore = function (range, originData, pasteData) {
            return
          }
        }
        _4(setting)
      }

      // 调整保存模型时的校验
      if (saveModelDefine) {
        let userName = JSON.parse(user)?.userName || ''
        var oldSaveModelDefineStr = `function saveModelDefine() {\n        var sheetfile = [];\n        let bChange = false;\n\n        let modelName = luckysheet.getCellValue(1, 1, {order: 0});\n        let modelCode = luckysheet.getCellValue(0, 1, {order: 0});\n        if (isEmpty(modelName) || isEmpty(modelCode)) {\n            alert("表代码或表名名称不能为空");\n            return false;\n        }else if(modelCode.includes(".")){\n            alert("表代码不能包含点号");\n            return false;\n        }\n        if(modelCode.toLowerCase()=="modeldemo"){\n            alert("请修改一下数据表代码");\n            return false;\n        }\n        if (!validKey.test(modelCode)) {\n            alert("表代码不能包含特殊字符和汉字");\n            return false;\n        }\n        if (changeList.includes(0)) {\n            bChange = true;\n        }\n        let sheet = luckysheet.getSheet({order: 0});\n        sheet.data[0][3].v = (new Date()).toLocaleString(); //修改【版本日期】\n        sheet.data[0][3].m = sheet.data[0][3].v;\n        sheet.data[0][6].v = "${userName}";   //修改【版本人】\n        sheet.data[0][6].m = sheet.data[0][6].v;\n        if (isEmpty(sheet.data[1][3].v)) {\n            sheet.data[1][3].v = (new Date()).toLocaleString(); //创建时间\n            sheet.data[1][3].m = sheet.data[1][3].v;\n            sheet.data[1][6].v = "${userName}";   //创建人\n            sheet.data[1][6].m = sheet.data[1][6].v;\n        }\n        sheet.celldata = "";  //清除没用的数据,减小体积\n        //let excel = luckysheet.getAllSheets();\n        //console.log(excel)\n\n        for (var i = 4; i < sheet.data.length; i++) { //第5行开始是字段定义行\n            var row = sheet.data[i];\n            //console.log(row)\n            if (row[0] == null) {\n                sheet.data.splice(i, 1);\n                continue;\n            }\n            var value = row[0].v;\n            if (value == null || value == undefined) {\n                continue;\n            }\n            if (!validKey.test(value)) {\n                luckysheet.toolTip("info", "错误", "字段代码不能包含特殊字符和汉字：" + value);\n                return false;\n            }\n            var ret = luckysheet.find(value, {isWholeWord: true, range: {row: [4, 10000], column: [0, 0]}})\n            if (ret.length > 1) {\n                luckysheet.toolTip("info", "错误", "字段代码【" + value + "】重复");\n                return false;\n            }\n            if (row[1] == null || row[1].v == undefined) {\n                luckysheet.toolTip("info", "错误", "字段代码【" + value + "】未定义字段名称");\n                return false;\n            }\n            value = row[1].v;\n            ret = luckysheet.find(value, {isWholeWord: true, range: {row: [4, 10000], column: [1, 1]}})\n            if (ret.length > 1) {\n                luckysheet.toolTip("info", "错误", "字段名称【" + value + "】重复");\n                return false;\n            }\n            if (isEmpty(row[5].v)) {\n                luckysheet.toolTip("info", "错误", "字段名称【" + value + "】数据类型未指定");\n                return false;\n            } else {\n                if (['VARCHAR', 'NUMBER'].includes(row[5].v) && isEmpty(row[6].v)) {\n                    luckysheet.toolTip("info", "错误", "字段名称【" + value + "】数据长度未指定");\n                    return false;\n                }\n            }\n        }\n\n        sheet.celldata = "";  //清除没用的数据,减小体积\n        let dataVerification = {...(sheet.dataVerification)};\n        let keys = Object.keys(dataVerification);\n        sheet.dataVerification = keys.reduce((obj, key) => { //保留checkbox\n            if (dataVerification[key].type == 'checkbox') {\n                obj[key] = dataVerification[key];\n            }\n            return obj;\n        }, {});\n        sheetfile.push(sheet)\n\n        if (changeList.includes(1)) {\n            sheet = luckysheet.getSheet({order: 1});\n            sheet.celldata = "";  //清除没用的数据,减小体积\n            dataVerification = {...(sheet.dataVerification)};\n            keys = Object.keys(dataVerification);\n            sheet.dataVerification = keys.reduce((obj, key) => {\n                if (dataVerification[key].type == 'checkbox') {\n                    obj[key] = dataVerification[key];\n                }\n                return obj;\n            }, {});\n            sheetfile.push(sheet)\n            bChange = true;\n        }else{  //没修改就不要填充数据了\n            sheetfile.push({})\n        }\n        if (changeList.includes(2)) {\n            sheet = luckysheet.getSheet({order: 2});\n            sheet.celldata = "";  //清除没用的数据,减小体积\n            dataVerification = {...(sheet.dataVerification)};\n            keys = Object.keys(dataVerification);\n            sheet.dataVerification = keys.reduce((obj, key) => {\n                if (dataVerification[key].type == 'checkbox') {\n                    obj[key] = dataVerification[key];\n                }\n                return obj;\n            }, {});\n            sheetfile.push(sheet)\n            bChange = true;\n        }else{  //没修改就不要填充数据了\n            sheetfile.push({})\n        }\n        if(bChange){\n            var sheetfileString = encodeURIComponent(JSON.stringify(sheetfile));\n            var compressed = pako.gzip(sheetfileString); // 不使用{to: "string"}选项\n            var arrayBuffer = compressed.buffer; // 获取ArrayBuffer\n            var base64Data = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer))); // 转换为Base64字符串\n            $.ajax({\n                url: "dataModelService.jsp?MOD=saveModelDefine",\n                type: "POST",\n                //data: {appId: appId,appBranch:encodeURIComponent(appBranch), modelCode: modelCode,modelId:modelInfo.id, jsonExcel: encodeURIComponent(JSON.stringify(sheetfile))},\n                data: {appId: appId,appBranch:encodeURIComponent(appBranch), modelCode: modelCode,modelId:modelInfo.id, jsonExcel: base64Data},\n                async:false,\n                dataType: "JSON",\n                success: function (ret) {\n                    if (ret && ret['CODE'] && parseInt(ret['CODE']) > 0) {\n                        $("#luckysheet_info_detail_save").text("已保存")\n                    } else {\n                        alert("保存模型定义出错," + ret['NOTE']);\n                        return false;\n                    }\n                }, error: function (text, msg, e) {\n                    alert("会话已过期!");\n                    return false;\n                }\n            });\n        }\n        if(changeList.includes(0) && isChangeModelCode){\n            isChangeModelCode = false;\n            $("#luckysheet-input-box").css("top",-1000) //这个是为了避免上次公式框内容带到下个sheet的单元格中\n            luckysheet.loadSheet({},0,"dataModelService.jsp?MOD=readModelDefine&appBranch="+encodeURIComponent(appBranch)+"&appId="+appId+"&modelCode="+modelInfo.modelCode+"&version="+(version?encodeURIComponent(version):"")+"&type=1");\n        }\n        changeList=[];\n        window.parent.postMessage({type: "changeModelStatus",status:false}, '/')\n        if(isChangeTree){\n            if(saveModelTree("update",null,modelInfo,null,null,null)==null) return false;\n        }\n        $("#luckysheet-icon-save", container).attr("style", "color:#abb0b5");\n        return true;\n    }`
        // 当函数是此版本内容时，才修改,否则弹出提示，需要更新脚本
        if (oldSaveModelDefineStr === saveModelDefine.toString()) {
          saveModelDefine = function saveModelDefine() {
            var sheetfile = []
            let bChange = false

            let modelName = luckysheet.getCellValue(1, 1, { order: 0 })
            let modelCode = luckysheet.getCellValue(0, 1, { order: 0 })
            if (isEmpty(modelName) || isEmpty(modelCode)) {
              createAlert('表代码或表名名称不能为空', 'error')
              return false
            } else if (modelCode.includes('.')) {
              createAlert('表代码不能包含点号', 'error')
              return false
            }
            if (modelCode.toLowerCase() == 'modeldemo') {
              createAlert('请修改一下数据表代码', 'error')
              return false
            }
            if (!validKey.test(modelCode)) {
              createAlert('表代码不能包含特殊字符和汉字', 'error')
              return false
            }
            if (changeList.includes(0)) {
              bChange = true
            }
            let sheet = luckysheet.getSheet({ order: 0 })
            let userName = JSON.parse(user)?.userName || ''

            sheet.data[0][3].v = new Date().toLocaleString() //修改【版本日期】
            sheet.data[0][3].m = sheet.data[0][3].v
            sheet.data[0][6].v = userName //修改【版本人】
            sheet.data[0][6].m = sheet.data[0][6].v
            if (isEmpty(sheet.data[1][3].v)) {
              sheet.data[1][3].v = new Date().toLocaleString() //创建时间
              sheet.data[1][3].m = sheet.data[1][3].v
              sheet.data[1][6].v = userName //创建人
              sheet.data[1][6].m = sheet.data[1][6].v
            }
            sheet.celldata = '' //清除没用的数据,减小体积
            //let excel = luckysheet.getAllSheets();
            //console.log(excel)

            for (var i = 4; i < sheet.data.length; i++) {
              //第5行开始是字段定义行
              var row = sheet.data[i]
              //console.log(row)
              if (row[0] == null) {
                sheet.data.splice(i, 1)
                continue
              }
              var value = row[0].v
              // 避免新模型不能修改名称就保存
              if (value == null || value == undefined || value == '') {
                continue
              }
              if (!validKey.test(value)) {
                createAlert('字段代码不能包含特殊字符和汉字：' + value, 'error')
                return false
              }
              var ret = luckysheet.find(value, { isWholeWord: true, range: { row: [4, 10000], column: [0, 0] }, order: 1})
              if (ret.length > 1) {
                createAlert('字段代码【' + value + '】重复', 'error')
                return false
              }
              /*if (row[1] == null || row[1].v == undefined) {
                  luckysheet.toolTip("info", "错误", "字段代码【" + value + "】未定义字段名称");
                  return false;
              }*/
              var name = row[1].v || ''
              ret = luckysheet.find(name, { isWholeWord: true, range: { row: [4, 10000], column: [1, 1] }, order: 1})
              if (ret.length > 1) {
                createAlert('字段名称【' + name + '】重复', 'error')
                return false
              }
              if (isEmpty(row[5].v)) {
                createAlert('字段代码【' + value + '】数据类型未指定', 'error')
                return false
              } else {
                if (['VARCHAR', 'NUMBER'].includes(row[5].v) && isEmpty(row[6].v)) {
                  createAlert('字段代码【' + value + '】数据长度未指定', 'error')
                  return false
                }
              }
            }

            sheet.celldata = '' //清除没用的数据,减小体积
            let dataVerification = { ...sheet.dataVerification }
            let keys = Object.keys(dataVerification)
            sheet.dataVerification = keys.reduce((obj, key) => {
              //保留checkbox
              if (dataVerification[key].type == 'checkbox') {
                obj[key] = dataVerification[key]
              }
              return obj
            }, {})
            sheetfile.push(sheet)

            if (changeList.includes(1)) {
              sheet = luckysheet.getSheet({ order: 1 })
              sheet.celldata = '' //清除没用的数据,减小体积
              dataVerification = { ...sheet.dataVerification }
              keys = Object.keys(dataVerification)
              sheet.dataVerification = keys.reduce((obj, key) => {
                if (dataVerification[key].type == 'checkbox') {
                  obj[key] = dataVerification[key]
                }
                return obj
              }, {})
              sheetfile.push(sheet)
              bChange = true
            } else {
              //没修改就不要填充数据了
              sheetfile.push({})
            }
            if (changeList.includes(2)) {
              sheet = luckysheet.getSheet({ order: 2 })
              sheet.celldata = '' //清除没用的数据,减小体积
              dataVerification = { ...sheet.dataVerification }
              keys = Object.keys(dataVerification)
              sheet.dataVerification = keys.reduce((obj, key) => {
                if (dataVerification[key].type == 'checkbox') {
                  obj[key] = dataVerification[key]
                }
                return obj
              }, {})
              sheetfile.push(sheet)
              bChange = true
            } else {
              //没修改就不要填充数据了
              sheetfile.push({})
            }
            if (bChange) {
              var sheetfileString = encodeURIComponent(JSON.stringify(sheetfile))
              var compressed = pako.gzip(sheetfileString) // 不使用{to: "string"}选项
              var arrayBuffer = compressed.buffer // 获取ArrayBuffer
              var base64Data = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer))) // 转换为Base64字符串
              $.ajax({
                url: 'dataModelService.jsp?MOD=saveModelDefine',
                type: 'POST',
                data: {
                  appId: appId,
                  appBranch: encodeURIComponent(appBranch),
                  modelCode: modelCode,
                  modelId: modelInfo.id,
                  jsonExcel: base64Data,
                },
                async: false,
                dataType: 'JSON',
                success: function (ret) {
                  if (ret && ret['CODE'] && parseInt(ret['CODE']) > 0) {
                    $('#luckysheet_info_detail_save').text('已保存')
                  } else {
                    createAlert('保存模型定义出错,' + ret['NOTE'], 'error')
                    return false
                  }
                },
                error: function (text, msg, e) {
                  createAlert('会话已过期!', 'error')
                  return false
                },
              })
            }
            if (changeList.includes(0) && isChangeModelCode) {
              isChangeModelCode = false
              $('#luckysheet-input-box').css('top', -1000) //这个是为了避免上次公式框内容带到下个sheet的单元格中
              luckysheet.loadSheet(
                {},
                0,
                'dataModelService.jsp?MOD=readModelDefine&appBranch=' +
                  encodeURIComponent(appBranch) +
                  '&appId=' +
                  appId +
                  '&modelCode=' +
                  modelInfo.modelCode +
                  '&version=' +
                  (version ? encodeURIComponent(version) : '') +
                  '&type=1'
              )
            }
            changeList = []
            window.parent.postMessage({ type: 'changeModelStatus', status: false }, '/')
            if (isChangeTree) {
              if (saveModelTree('update', null, modelInfo, null, null, null) == null) return false
            }
            $('#luckysheet-icon-save', container).attr('style', 'color:#abb0b5')
            var msg = '已保存'
            if (luckysheet.getSheet().order == 0) {
              msg += '模型'
            } else if (luckysheet.getSheet().order == 1) {
              msg += '索引'
            } else if (luckysheet.getSheet().order == 2) {
              msg += '属性'
            }
            createAlert(msg, 'success', 1000)
            return true
          }
        } else if (
          !saveModelDefine.toString().includes('saveModelDefine.toString()') ||
          !saveModelDefine.toString().includes("let userName = JSON.parse(user)?.userName || ''")
        ) {
          createAlert('网站函数 saveModelDefine 有更新，请更新对应脚本内容', 'warning')
        }
      }

      // 调整打开模型的函数，这里会判断，如果模型还是初始模型，则将修改人改为当前用户
      if (selectModel) {
        let userName = JSON.parse(user)?.userName || ''
        var oldFuncStr = `function selectModel(event, treeId, treeNode){\n        $("#fuzzySearch").hide();\n        $("#modelDef").show();\n        if(changeList.length>0){\n            let v = window.confirm("【"+modelInfo.name+"】有修改还未保存，是否保存？");\n            if(v==true){\n                if(!saveModelDefine()){\n                    return false;\n                }\n                if(isChangeTree){\n                    saveModelTree("update",null,modelInfo,null,null,null);\n                }\n            }else{\n                changeList = [];\n                window.parent.postMessage({type: "changeModelStatus",status:false}, '/')\n            }\n        }\n        $("#luckysheet-icon-save", container).attr("style", "color:#abb0b5");\n        $(".luckysheet-freezebar-vertical-drop-bar",$("#modelDefineSheet")).attr("style", "background:#f2f0f0");\n        //console.log(event,treeId,treeNode);\n        if(treeNode==undefined) return;\n\n        modelInfo = treeNode; //zTree.getNodeByTId(treeNode.tId);\n        if( treeNode!=undefined && treeNode.isParent){\n            modelInfo["modelName"]="字段定义";\n            modelInfo["modelCode"]="modelDemo";\n        }\n\n        /*var sheetObject;\n        $.ajax({\n            url: "dataModelService.jsp?MOD=readModelDefine",\n            data: {appId:appId,appBranch:encodeURIComponent(appBranch),modelCode:modelInfo.modelCode},\n            method: "POST",\n            async: false,\n            dataType: 'json',\n            success: function (ret) {\n                if (ret!=null) {\n                    sheetObject =  ret\n                    //sheetObject.index = modelInfo.modelCode;\n                }else{\n                    sheetObject={name:modelInfo.modelName,index:modelInfo.modelCode,\n                                config:{"columnlen":{"0": 200,"1": 200,"2": 160,"3": 90,"6": 300}}\n                                };\n                }\n            }\n        });\n        luckysheet.updataSheet({data:sheetObject})*/\n        $("#modelDefineSheet").css("pointer-events","none");  //冻结表格页面\n        loadingSheet = true;\n        $("#luckysheet-input-box").css("top",-1000) //这个是为了避免上次公式框内容带到下个sheet的单元格中\n        luckysheet.loadSheet({},0,"dataModelService.jsp?MOD=readModelDefine&appId="+appId+"&appBranch="+encodeURIComponent(appBranch)+"&modelCode="+modelInfo.modelCode+"&version="+(version?encodeURIComponent(version):"")+"&type=1",\n            {success:function (sheet) {\n                if(modelInfo.modelCode=="modelDemo"){\n                    luckysheet.setCellValue(1,3,(new Date()).toLocaleString(), {order: 0, isRefresh: false});\n                    luckysheet.setCellValue(1,6,"${userName}", {order: 0});\n                }\n                if(luckysheet.getCellValue(2,5)!="任务编号") {\n                    luckysheet.cancelRangeMerge({range: "B3:J3", order: 0});\n                    luckysheet.setRangeMerge("horizontal", {range: "B3:E3", order: 0});\n                    luckysheet.setRangeMerge("horizontal", {range: "G3:H3", order: 0});\n                    luckysheet.setCellValue(2, 5, {\n                        m: "任务编号",\n                        v: "任务编号",\n                        bg: "rgb(238, 238, 238)",\n                        fc:"#ff0000",\n                        ht: 0,\n                        vt: 0\n                    }, {order: 0});\n                }\n                luckysheet.setDataVerification({\n                    "type": "number_integer",\n                    "type2": "bw",\n                    "value1": "1",\n                    "value2": "999999",\n                    "prohibitInput": true,\n                    "hintShow": true,\n                    "hintText": "填写开发任务编号，用于发布时筛选"\n                }, {range: "G3", order: 0});\n                loadingSheet = false;\n                $("#modelDefineSheet").css("pointer-events","");  //激活表格页面\n            }\n            });\n\n        selectTab[0].click();\n\n    }`
        if (oldFuncStr === selectModel.toString()) {
          selectModel = async function selectModel(event, treeId, treeNode) {
            $('#fuzzySearch').hide()
            $('#modelDef').show()
            if (changeList.length > 0) {
              const result = await Swal.fire({
                title: '提示',
                html: `<span class="swal2-content">【${modelInfo.name}】有修改还未保存，是否保存？</span>`,
                icon: 'warning',
                showCloseButton: false,
                showConfirmButton: true,
                confirmButtonText: '确认',
                showCancelButton: true,
                cancelButtonText: '取消',
              })
              if (result.isConfirmed) {
                if (!saveModelDefine()) {
                  return false
                }
                if (isChangeTree) {
                  saveModelTree('update', null, modelInfo, null, null, null)
                }
              } else if (result.dismiss === Swal.DismissReason.cancel) {
                changeList = []
                window.parent.postMessage({ type: 'changeModelStatus', status: false }, '/')
              }
            }
            $('#luckysheet-icon-save', container).attr('style', 'color:#abb0b5')
            $('.luckysheet-freezebar-vertical-drop-bar', $('#modelDefineSheet')).attr('style', 'background:#f2f0f0')
            if (treeNode == undefined) return

            modelInfo = treeNode
            if (treeNode != undefined && treeNode.isParent) {
              modelInfo['modelName'] = '字段定义'
              modelInfo['modelCode'] = 'modelDemo'
            }
            $('#modelDefineSheet').css('pointer-events', 'none') //冻结表格页面
            loadingSheet = true
            $('#luckysheet-input-box').css('top', -1000) //这个是为了避免上次公式框内容带到下个sheet的单元格中
            luckysheet.loadSheet(
              {},
              0,
              'dataModelService.jsp?MOD=readModelDefine&appId=' +
                appId +
                '&appBranch=' +
                encodeURIComponent(appBranch) +
                '&modelCode=' +
                modelInfo.modelCode +
                '&version=' +
                (version ? encodeURIComponent(version) : '') +
                '&type=1',
              {
                success: function (sheet) {
                  if (modelInfo.modelCode.includes('modelDemo')) {
                    luckysheet.setCellValue(1, 3, new Date().toLocaleString(), { order: 0, isRefresh: false })
                    let userName = JSON.parse(user)?.userName || ''
                    luckysheet.setCellValue(1, 6, userName, { order: 0 })
                  }
                  if (luckysheet.getCellValue(2, 5) != '任务编号') {
                    luckysheet.cancelRangeMerge({ range: 'B3:J3', order: 0 })
                    luckysheet.setRangeMerge('horizontal', { range: 'B3:E3', order: 0 })
                    luckysheet.setRangeMerge('horizontal', { range: 'G3:H3', order: 0 })
                    luckysheet.setCellValue(
                      2,
                      5,
                      {
                        m: '任务编号',
                        v: '任务编号',
                        bg: 'rgb(238, 238, 238)',
                        fc: '#ff0000',
                        ht: 0,
                        vt: 0,
                      },
                      { order: 0 }
                    )
                  }
                  luckysheet.setDataVerification(
                    {
                      type: 'number_integer',
                      type2: 'bw',
                      value1: '1',
                      value2: '999999',
                      prohibitInput: true,
                      hintShow: true,
                      hintText: '填写开发任务编号，用于发布时筛选',
                    },
                    { range: 'G3', order: 0 }
                  )
                  const sheet1Data = luckysheet.toJson().data[0]
                  // 删除小数位数校验，现在才12位
                  luckysheet.deleteDataVerification({
                    range: { row: [4, sheet1Data.row - 1], column: [7, 7] },
                    order: 0,
                  })
                  loadingSheet = false
                  $('#modelDefineSheet').css('pointer-events', '') //激活表格页面
                },
              }
            )

            selectTab[0].click()
          }
        } else if (
          !selectModel.toString().includes('modelInfo.modelCode=="modelDemo"') ||
          !selectModel.toString().includes("let userName = JSON.parse(user)?.userName || ''")
        ) {
          createAlert('网站函数 selectModel 有更新，请更新对应脚本内容', 'warning')
        }
      }
    };

		const originalInit = sheetIframe.contentWindow.$.fn.zTree.init;
		sheetIframe.contentWindow.$.fn.zTree.init = function(container, settings, zNodes) {
      const treeObj = originalInit.apply(this, arguments);
      // 在此执行自定义逻辑（如修改节点、添加按钮等）
      // 优化新增模型节点时，不能重复新增多个默认节点的问题

      // 重写节点点击事件
      /*if (treeObj?.setting?.callback?.onClick) {
        var originFuncStr =
          'async function selectModel(event, treeId, treeNode){\n\t\t\t\t\t\t\t$("#fuzzySearch").hide();\n\t\t\t\t\t\t\t$("#modelDef").show();\n\t\t\t\t\t\t\tif(changeList.length>0){\n                const result = await Swal.fire({\n                  title: \'提示\',\n                  html: `<span class="swal2-content">【${modelInfo.name}】有修改还未保存，是否保存？</span>`,\n                  icon: \'warning\',\n                  showCloseButton: false,\n                  showConfirmButton: true,\n                  confirmButtonText: \'确认\',\n                  showCancelButton: true,\n                  cancelButtonText: \'取消\'\n                });\n                if (result.isConfirmed) {\n                  if(!saveModelDefine()){\n                    return false;\n                  }\n                  if(isChangeTree){\n                    saveModelTree("update",null,modelInfo,null,null,null);\n                  }\n                } else if (result.dismiss === Swal.DismissReason.cancel) {\n                  changeList = [];\n                  window.parent.postMessage({type: "changeModelStatus",status:false}, \'/\')\n                }\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t$("#luckysheet-icon-save", container).attr("style", "color:#abb0b5");\n\t\t\t\t\t\t\t$(".luckysheet-freezebar-vertical-drop-bar",$("#modelDefineSheet")).attr("style", "background:#f2f0f0");\n\t\t\t\t\t\t\tif(treeNode==undefined) return;\n\n\t\t\t\t\t\t\tmodelInfo = treeNode;\n\t\t\t\t\t\t\tif( treeNode!=undefined && treeNode.isParent){\n\t\t\t\t\t\t\t\t\tmodelInfo["modelName"]="字段定义";\n\t\t\t\t\t\t\t\t\tmodelInfo["modelCode"]="modelDemo";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t$("#modelDefineSheet").css("pointer-events","none");  //冻结表格页面\n\t\t\t\t\t\t\tloadingSheet = true;\n\t\t\t\t\t\t\t$("#luckysheet-input-box").css("top",-1000) //这个是为了避免上次公式框内容带到下个sheet的单元格中\n\t\t\t\t\t\t\tluckysheet.loadSheet({},0,"dataModelService.jsp?MOD=readModelDefine&appId="+appId+"&appBranch="+encodeURIComponent(appBranch)+"&modelCode="+modelInfo.modelCode+"&version="+(version?encodeURIComponent(version):"")+"&type=1",\n\t\t\t\t\t\t\t\t\t{success:function (sheet) {\n\t\t\t\t\t\t\t\t\t\t\tif(modelInfo.modelCode.includes("modelDemo")){\n\t\t\t\t\t\t\t\t\t\t\t\t\tluckysheet.setCellValue(1,3,(new Date()).toLocaleString(), {order: 0, isRefresh: false});\n\t\t\t\t\t\t\t\t\t\t\t\t\tlet userName = JSON.parse(user)?.userName || \'\'\n\t\t\t\t\t\t\t\t\t\t\t\t\tluckysheet.setCellValue(1,6,userName, {order: 0});\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tif(luckysheet.getCellValue(2,5)!="任务编号") {\n\t\t\t\t\t\t\t\t\t\t\t\t\tluckysheet.cancelRangeMerge({range: "B3:J3", order: 0});\n\t\t\t\t\t\t\t\t\t\t\t\t\tluckysheet.setRangeMerge("horizontal", {range: "B3:E3", order: 0});\n\t\t\t\t\t\t\t\t\t\t\t\t\tluckysheet.setRangeMerge("horizontal", {range: "G3:H3", order: 0});\n\t\t\t\t\t\t\t\t\t\t\t\t\tluckysheet.setCellValue(2, 5, {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tm: "任务编号",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tv: "任务编号",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbg: "rgb(238, 238, 238)",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfc:"#ff0000",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tht: 0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tvt: 0\n\t\t\t\t\t\t\t\t\t\t\t\t\t}, {order: 0});\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tluckysheet.setDataVerification({\n\t\t\t\t\t\t\t\t\t\t\t\t\t"type": "number_integer",\n\t\t\t\t\t\t\t\t\t\t\t\t\t"type2": "bw",\n\t\t\t\t\t\t\t\t\t\t\t\t\t"value1": "1",\n\t\t\t\t\t\t\t\t\t\t\t\t\t"value2": "999999",\n\t\t\t\t\t\t\t\t\t\t\t\t\t"prohibitInput": true,\n\t\t\t\t\t\t\t\t\t\t\t\t\t"hintShow": true,\n\t\t\t\t\t\t\t\t\t\t\t\t\t"hintText": "填写开发任务编号，用于发布时筛选"\n\t\t\t\t\t\t\t\t\t\t\t}, {range: "G3", order: 0});\n\t\t\t\t\t\t\t\t\t\t\tloadingSheet = false;\n\t\t\t\t\t\t\t\t\t\t\t$("#modelDefineSheet").css("pointer-events","");  //激活表格页面\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tselectTab[0].click();\n\n\t\t\t\t\t}'
        if (treeObj.setting.callback.onClick.toString() == originFuncStr) {
          treeObj.setting.callback.onClick = async function selectModel(event, treeId, treeNode) {
            $('#fuzzySearch').hide()
            $('#modelDef').show()
            if (changeList.length > 0) {
              const result = await Swal.fire({
                title: '提示',
                html: `<span class="swal2-content">【${modelInfo.name}】有修改还未保存，是否保存？</span>`,
                icon: 'warning',
                showCloseButton: false,
                showConfirmButton: true,
                confirmButtonText: '确认',
                showCancelButton: true,
                cancelButtonText: '取消',
              })
              if (result.isConfirmed) {
                if (!saveModelDefine()) {
                  return false
                }
                if (isChangeTree) {
                  saveModelTree('update', null, modelInfo, null, null, null)
                }
              } else if (result.dismiss === Swal.DismissReason.cancel) {
                changeList = []
                window.parent.postMessage({ type: 'changeModelStatus', status: false }, '/')
              }
            }
            $('#luckysheet-icon-save', container).attr('style', 'color:#abb0b5')
            $('.luckysheet-freezebar-vertical-drop-bar', $('#modelDefineSheet')).attr('style', 'background:#f2f0f0')
            if (treeNode == undefined) return

            modelInfo = treeNode
            if (treeNode != undefined && treeNode.isParent) {
              modelInfo['modelName'] = '字段定义'
              modelInfo['modelCode'] = 'modelDemo'
            }
            $('#modelDefineSheet').css('pointer-events', 'none') //冻结表格页面
            loadingSheet = true
            $('#luckysheet-input-box').css('top', -1000) //这个是为了避免上次公式框内容带到下个sheet的单元格中
            luckysheet.loadSheet(
              {},
              0,
              'dataModelService.jsp?MOD=readModelDefine&appId=' +
                appId +
                '&appBranch=' +
                encodeURIComponent(appBranch) +
                '&modelCode=' +
                modelInfo.modelCode +
                '&version=' +
                (version ? encodeURIComponent(version) : '') +
                '&type=1',
              {
                success: function (sheet) {
                  if (modelInfo.modelCode.includes('modelDemo')) {
                    luckysheet.setCellValue(1, 3, new Date().toLocaleString(), { order: 0, isRefresh: false })
                    let userName = JSON.parse(user)?.userName || ''
                    luckysheet.setCellValue(1, 6, userName, { order: 0 })
                  }
                  if (luckysheet.getCellValue(2, 5) != '任务编号') {
                    luckysheet.cancelRangeMerge({ range: 'B3:J3', order: 0 })
                    luckysheet.setRangeMerge('horizontal', { range: 'B3:E3', order: 0 })
                    luckysheet.setRangeMerge('horizontal', { range: 'G3:H3', order: 0 })
                    luckysheet.setCellValue(
                      2,
                      5,
                      {
                        m: '任务编号',
                        v: '任务编号',
                        bg: 'rgb(238, 238, 238)',
                        fc: '#ff0000',
                        ht: 0,
                        vt: 0,
                      },
                      { order: 0 }
                    )
                  }
                  luckysheet.setDataVerification(
                    {
                      type: 'number_integer',
                      type2: 'bw',
                      value1: '1',
                      value2: '999999',
                      prohibitInput: true,
                      hintShow: true,
                      hintText: '填写开发任务编号，用于发布时筛选',
                    },
                    { range: 'G3', order: 0 }
                  )
                  loadingSheet = false
                  $('#modelDefineSheet').css('pointer-events', '') //激活表格页面
                },
              }
            )

            selectTab[0].click()
          }
        } else if (!treeObj.setting.callback.onClick.toString().includes('// 默认添加开放范围验证')) {
          createAlert('函数 zTree.setting.callback.onClick 版本有变动，请更新脚本代码', 'error')
        }
      } else {
        createAlert('函数 zTree.setting.callback.onClick 还未加载', 'warning')
      }*/

      // 重写节点处理新增按钮
			if(treeObj?.setting?.view?.addHoverDom?.toString()){
				var oldFuncStr = `function zTreeAddHoverDom(treeId, treeNode) {\n            if((treeNode.isParent==false && treeNode.pId!=null ) || authType==0) return false;\n            if (treeNode.editNameFlag || $("#addBtn_"+treeNode.tId).length>0) return;\n            var sObj = $("#" + treeNode.tId + "_a");\n            var addStr = "<span class='button add' id='addBtn_" + treeNode.tId+"' tId='"+treeNode.tId+"' title='add node' onfocus='this.blur();'></span>";\n            sObj.append(addStr);\n\n            var btn = $("#addBtn_"+treeNode.tId,$("#modelTree"));\n            if (btn) btn.bind("click", function(){ //新增叶子（model）\n                refreshTree(appId,appBranch);\n                var pNode = zTree.getNodeByTId($(this).attr("tId"));\n                var now = new Date();\n                //var time = now.toLocaleString().substring(12,20).replaceAll(":","").padStart(4,"0"); //截取时间\n                //var id = Date.parse(now)/1000;\n                var id = snowflake.nextId();\n                var newNode ={id:id, pId:pNode.id, name:"Model"+id,modelName:"Model"+id,modelCode:"modelDemo",version:"dev"};\n                newNode = saveModelTree("add",null,newNode,pNode,null,null);\n                $("#" + newNode.tId + "_span").click();\n                return false;\n            });\n\n        }`;
				if(treeObj?.setting?.view?.addHoverDom?.toString() == oldFuncStr){
					treeObj.setting.view.addHoverDom = function (treeId, treeNode) {
						if((treeNode.isParent==false && treeNode.pId!=null ) || authType==0) return false;
						if (treeNode.editNameFlag || $("#addBtn_"+treeNode.tId).length>0) return;
						var sObj = $("#" + treeNode.tId + "_a");
						var addStr = "<span class='button add' id='addBtn_" + treeNode.tId+"' tId='"+treeNode.tId+"' title='add node' onfocus='this.blur();'></span>";
						sObj.append(addStr);

						var btn = $("#addBtn_"+treeNode.tId,$("#modelTree"));
						if (btn) btn.bind("click", function(){ //新增叶子（model）
								refreshTree(appId,appBranch);
								var pNode = zTree.getNodeByTId($(this).attr("tId"));
								var now = new Date();
								var id = snowflake.nextId();
								var newNode ={id:id, pId:pNode.id, name:"Model"+id,modelName:"Model"+id,modelCode:"modelDemo"+id,version:"dev"};
								newNode = saveModelTree("add",null,newNode,pNode,null,null);
								$("#" + newNode.tId + "_span").click();
								return false;
						});
					};
				} else if (!treeObj?.setting?.view?.addHoverDom?.toString().includes(`"modelDemo"+id`) || !treeObj?.setting?.view?.addHoverDom?.toString().includes(`modelCode:"modelDemo",`)){
					createAlert('网站函数 zTree.setting.view.addHoverDom 有更新，请更新对应脚本内容', 'warning')
				}
			}else {
				createAlert('网站函数 zTree.setting.view.addHoverDom 还未加载', 'warning')
			}

				return treeObj;
		};


  });

  GM_addStyle(`
		/* 产品接口文档 接口图标修正 */
		.ztree li span.button.ico_docu {
				background-position: -110px -31px !important;
		}
		.ztree li span.button {
				height: 14px !important;
		}
		.ztree li span.button.ico_open {
				background-position: -110px -15px !important;
		}
		.ztree li span.button.add {
				background-position: -144px 1px !important;
		}
		.ztree li span.button.edit {
				background-position: -110px -47px !important;
		}
		.ztree li span.button.chk.checkbox_false_full{
				background-position: 0 4 !important;
		}
		.ztree li span.button.chk.checkbox_false_full_focus {
				background-position: 0 -13 !important;
				max-height: 11 !important;
				margin-top: 3px !important;
		}
		.ztree li span.button.chk.checkbox_true_full {
				background-position: -14 4 !important;
		}
		.ztree li span.button.chk.checkbox_true_full_focus {
				background-position: -14px -13px !important;
				max-height: 11 !important;
				margin-top: 3 !important;
		}
		.ztree li span.button.chk.checkbox_true_part {
				background-position: 0 -13px !important;
				max-height: 11 !important;
				margin-top: 3 !important;
		}
		.ztree li span.button.chk.checkbox_true_part_focus {
				background-position: 0 -41 !important;
				max-height: 11 !important;
				margin-top: 3px !important;
		}

		/* 产品接口文档树 优化样式 */
		.ztree li a.curSelectedNode {
				background-color: bisque !important;
				height: 16px !important;
				border-radius: 3px;
		}
		.ztree li a {
				padding: 2px 0px 2px 0px !important;
				height: 17px !important;
				font-size: 13px !important;
		}
		.ztree li a:hover {
				background-color: bisque !important;
				padding: 2px 0px 2px 0px !important;
				font-size: 13px !important;
				border-radius: 3px;
		}
		#modelList{
			height: calc(100vh - 22px) !important;
			padding-top: 10px;
		}
		.ztree li a.tmpTargetNode_inner {
			background-color: #70B5FC !important;
			color:white; height:16px !important;
			border:1px #4191E2 solid !important;
			border-radius: 3px;
		}
		.ztree li a.curSelectedNode_Edit input.rename{
			width: fit-content ;
			font-size: 13px;
		}
		ul#modelTree {
			height: 93% !important;
		}
`)
}

async function refreshModelData(arg1, arg2) {
  var response = await fetch(
    'http://cowork.apexsoft.com.cn/plug-in/cowork/DataModelManage/dataModelService.jsp?MOD=downloadModelDef',
    {
      headers: {
        accept: 'application/json, text/javascript, */*; q=0.01',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7',
        'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'x-requested-with': 'XMLHttpRequest',
      },
      referrer: 'http://cowork.apexsoft.com.cn/plug-in/cowork/DataModelManage/appDataModelDesign.jsp?w=true',
      referrerPolicy: 'strict-origin-when-cross-origin',
      body: `appId=${arg1}&appBranch=${arg2}&type=0`,
      method: 'POST',
      mode: 'cors',
      credentials: 'include',
    }
  )
  if (!response.ok) {
    throw new Error('Network response was not ok ' + response.statusText)
  }
  return await response.json()
}

async function refreshDataType(arg1, arg2) {
  var response = await fetch(
    'http://cowork.apexsoft.com.cn/plug-in/cowork/DataModelManage/dataModelService.jsp?MOD=queryDotTemplateID&type=1',
    {
      headers: {
        accept: 'application/json, text/javascript, */*; q=0.01',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7',
        'x-requested-with': 'XMLHttpRequest',
      },
      referrer: `http://cowork.apexsoft.com.cn/plug-in/cowork/DataModelManage/sqlScriptPage.jsp?appId=${arg1}&appBranch=${arg2}&modelCode=undefined&authType=2`,
      referrerPolicy: 'strict-origin-when-cross-origin',
      body: null,
      method: 'GET',
      mode: 'cors',
      credentials: 'include',
    }
  )
  if (!response.ok) {
    throw new Error('Network response was not ok ' + response.statusText)
  }
  return await response.json()
}

/* 选中的叶子节点增加加新节点的按钮 */
function secModelNodeAddHoverDom(treeId, treeNode) {
  // if((treeNode.isParent==false && treeNode.pId!=null ) || authType==0) return false;
  if (treeNode.isParent == true || authType == 0) return false
  if (treeNode.editNameFlag || $('#addBtn_' + treeNode.tId).length > 0) return
  var sObj = $('#' + treeNode.tId + '_span')
  var addStr =
    "<span class='button add' id='addBtn_" +
    treeNode.tId +
    "' tId='" +
    treeNode.tId +
    "' title='add node' onfocus='this.blur();'></span>"
  sObj.after(addStr)

  var btn = $('#addBtn_' + treeNode.tId, $('#modelTree'))
  if (btn)
    btn.bind('click', function () {
      //新增叶子，并移动到当前节点下方
      var pNode = zTree.getNodeByTId(treeNode.parentTId)

			var id = snowflake.nextId();
      var newNode = {
        id: id,
        pId: pNode.id,
        name: "Model"+id,
        modelName: "Model"+id,
        modelCode: 'modelDemo'+id,
        version: 'dev',
      }
      newNode = saveModelTree('add', null, newNode, pNode, 'nodeAdd', null)

      // 移动到当前节点下方
      setTimeout(() => {
        var tNode = zTree.getNodesByParam('id', treeNode.id)
        var node = zTree.getNodesByParam('id', id)
        if (tNode.length == 1 && node.length == 1) {
          saveModelTree('move', null, node[0], tNode[0], 'next', false)
          setTimeout(() => {
            posiToCurrSelectedNode(id)
          }, 200)
        }
      }, 400)
      return false
    })
}
// 下划线<=>驼峰
function tranCamelCase(str) {
  if (str) {
    if (str.indexOf('_') > 0) {
      // 下划线->驼峰
      str = str.toLowerCase().replace(/_([a-z])/g, function (match, letter) {
        return letter.toUpperCase()
      })
    } else {
      // 驼峰->下划线
      str = str.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase()
    }
  }
  return str
}
// 选区 下划线<=>驼峰
function tranEngCamelCaseRange(ls, range) {
  range = range ? range : ls.getRange()
  if (range instanceof Array) {
    range.forEach((eRge) => {
      const eachselectedCells = ls.getRangeValue({ range: eRge })
      // 遍历选中区域的每一行
      eachselectedCells.forEach((row) => {
        // 遍历行中的每个单元格
        row.forEach((cell) => {
          if (cell && typeof cell.v === 'string') {
            cell.v = tranCamelCase(cell.v)
          }
          if (cell && typeof cell.m === 'string') {
            cell.m = tranCamelCase(cell.m)
          }
        })
      })
      // 更新单元格数据
      ls.setRangeValue(eachselectedCells, { range: eRge })
    })
  } else {
    const selectedCells = ls.getRangeValue({ range })
    // 遍历选中区域的每一行
    selectedCells.forEach((row) => {
      // 遍历行中的每个单元格
      row.forEach((cell) => {
        if (cell && typeof cell.v === 'string') {
          cell.v = tranCamelCase(cell.v)
        }
        if (cell && typeof cell.m === 'string') {
          cell.m = tranCamelCase(cell.m)
        }
      })
    })

    // 更新单元格数据
    ls.setRangeValue(selectedCells, { range })
  }
}
// 选区大小写调整
function tranEngCaseRange(ls, range) {
  range = range ? range : ls.getRange()

  if (range instanceof Array) {
    range.forEach((eRge) => {
      const eachselectedCells = ls.getRangeValue({ range: eRge })
      // 遍历选中区域的每一行
      eachselectedCells.forEach((row) => {
        // 遍历行中的每个单元格
        row.forEach((cell) => {
          if (cell && typeof cell.v === 'string') {
            cell.v = cell.v === cell.v.toUpperCase() ? cell.v.toLowerCase() : cell.v.toUpperCase()
          }
          if (cell && typeof cell.m === 'string') {
            cell.m = cell.m === cell.m.toUpperCase() ? cell.m.toLowerCase() : cell.m.toUpperCase()
          }
        })
      })
      // 更新单元格数据
      ls.setRangeValue(eachselectedCells, { range: eRge })
    })
  } else {
    const selectedCells = ls.getRangeValue({ range })
    // 遍历选中区域的每一行
    selectedCells.forEach((row) => {
      // 遍历行中的每个单元格
      row.forEach((cell) => {
        if (cell && typeof cell.v === 'string') {
          cell.v = cell.v === cell.v.toUpperCase() ? cell.v.toLowerCase() : cell.v.toUpperCase()
        }
        if (cell && typeof cell.m === 'string') {
          cell.m = cell.m === cell.m.toUpperCase() ? cell.m.toLowerCase() : cell.m.toUpperCase()
        }
      })
    })

    // 更新单元格数据
    ls.setRangeValue(selectedCells, { range })
  }
}

// 上下移动字段行 up down top bottom
function moveFieldRow(ls, moveType) {
  if (ls.toJson()?.data[0]) {
    const originalDataSnapshot = JSON.stringify(ls.toJson().data[0].data)

    const rowCnt = ls.toJson().data[0].row
    const columnCnt = ls.toJson().data[0].column
    const data = ls.toJson().data[0].data // 取整个表格的数据

    var rows = []

    var selectRanges = ls.getRange()

    // 校验选区必须是字段行 row >= 4
    for (var range of selectRanges) {
      // 针对每个选区进行检查，必须选中的是行
      if (range.row.length === 2 && range.column.length === 2) {
        if (
          range.row[0] <= range.row[1] &&
          range.row[0] >= 4 &&
          range.column[0] === 0 &&
          range.column[1] === columnCnt - 1
        ) {
          // 当前选区是合法行，将合法的行添加到rows中
          rows = [
            ...new Set([
              ...rows,
              ...Array(range.row[1] - range.row[0] + 1)
                .keys()
                .map((i) => range.row[0] + i),
            ]),
          ]
        } else {
          createAlert('请选中要移动的字段行', 'warning')
          return
        }
      } else {
        createAlert('当前选区数据有误', 'warning')
        console.warn('当前选区数据有误', JSON.stringify(range))
        return
      }
    }

    // 上移顺序处理，下移倒序处理
    if (moveType == 'up' || moveType == 'top') {
      rows.sort((a, b) => a - b)
    } else if (moveType == 'down' || moveType == 'bottom') {
      rows.sort((a, b) => b - a)
    }

    // 记录最终的实际行号
    var finalRowPositions = []

    for (var r of rows) {
      var exchangeRow
      if (moveType == 'up') {
        exchangeRow = r == 4 ? r : r - 1
      } else if (moveType == 'down') {
        exchangeRow = r == rowCnt - 1 ? r : r + 1
      } else if (moveType == 'top') {
        exchangeRow = 4
      } else if (moveType == 'bottom') {
        exchangeRow = rowCnt - 1
      }

      /*
              1. 上移、下移
                    如果目标位置和当前位置一致，说明到了顶部或底部，不再移动
                    如果目标位置 在 之前的元素的目标位置中，说明移动到了之前元素的位置，则不再移动
              2. 置顶
                    如果目标位置和当前位置一致，说明到了顶部，不再移动
                    如果目标位置 在 之前的元素的目标位置中，则说明已经有元素置顶了，则按顺序排到最大一行的下面
              3. 置底
                    如果目标位置和当前位置一致，说明到了底部，不再移动
                    如果目标位置 在 之前的元素的目标位置中，则说明已经有元素置底了，则按顺序排到最小一行的上面
              */

      // 交换行数据 || 如果已经有元素没有移动，则当前行移动到目标行时，也不处理

      if (moveType == 'up' || moveType == 'down') {
        if (exchangeRow != r && !finalRowPositions.includes(exchangeRow)) {
          var temp = data[r]
          data.splice(r, 1)
          data.splice(exchangeRow, 0, temp)
          // 记录最终的实际行号
          finalRowPositions.push(exchangeRow)
        } else {
          finalRowPositions.push(r)
        }
      } else if (moveType == 'top' || moveType == 'bottom') {
        // 置顶
        if (finalRowPositions.includes(exchangeRow)) {
          exchangeRow = moveType == 'top' ? Math.max(...finalRowPositions) + 1 : Math.min(...finalRowPositions) - 1
        }
        if (exchangeRow == r) {
          finalRowPositions.push(r)
        } else {
          var temp = data[r]
          data.splice(r, 1)
          data.splice(exchangeRow, 0, temp)
          finalRowPositions.push(exchangeRow)
        }
      }
    }

    // 更新整个表格的数据
    if (JSON.stringify(data) !== originalDataSnapshot) {
      ls.setRangeValue(data.slice(4), { range: { row: [4, rowCnt - 1], column: [0, columnCnt - 1] } });

			// 更新数据var验证 checkbox的选项内容
			const dataVerification = ls.toJson().data[0].dataVerification; // 缓存校验数据
			const verificationData = data
				.flatMap((rowArray, row) =>
					rowArray.map((item, column) => ({
						...item,
						row,
						column,
						// 使用缓存数据避免重复解析
						checked: item.checkboxRect
							? dataVerification[`${row}_${column}`]?.checked || false
							: undefined,
					}))
				)
				.filter((item) => item.checkboxRect && item.v !== item.checked);

			// 批量更新校验数据
			verificationData.forEach(({ row, column, v }) => {
				ls.setDataVerification(
					{
						type: "checkbox",
						value1: true,
						value2: false,
						checked: v,
					},
					{
						range: {
							row: [row, row],
							column: [column, column],
						},
					}
				);
			});


		}

    // 选中对应的行
    var selectedRanges = []
    finalRowPositions.sort((a, b) => a - b)
    function isConsecutivelyIncreasing(arr) {
      for (let i = 0; i < arr.length - 1; i++) {
        if (arr[i + 1] - arr[i] !== 1) {
          return false
        }
      }
      return true
    }

    if (isConsecutivelyIncreasing(finalRowPositions)) {
      // 如果行是连续的，创建一个选区
      selectedRanges.push({
        row: [Math.min(...finalRowPositions), Math.max(...finalRowPositions)],
        column: [0, columnCnt - 1],
      })
    } else {
      // 如果行不连续，为每个最终的实际行号创建单独的选区
      finalRowPositions.forEach((row) => {
        selectedRanges.push({
          row: [row, row],
          column: [0, columnCnt - 1],
        })
      })
    }

    // 选中对应的行
    ls.setRangeShow(selectedRanges)

    //createAlert(`已移动${rows.length}行`, 'success');
  }
}

// 模型定义：添加一键调整合适宽度；接口定义说明优化;修改日志美化
function addAjustWidthToModel() {
  // 增强，在sheet中增加调整宽度的按钮
  elmGetter.each('#modelDefineSheet #luckysheet-wa-editor', document, (waEditor) => {
    // 分割线
    var sepDivHtml = `<div id='toolbar-separator-merge-cell' class='luckysheet-toolbar-separator luckysheet-inline-block' style='user-select: none;'/>`
    var sepDiv = createDivByHtml(sepDivHtml)
    var sepDiv2 = createDivByHtml(sepDivHtml)
    var sepDiv3 = createDivByHtml(sepDivHtml)

    // ----------------------------------------- 优化操作手感
    // 去除鼠标移动事件，移除编辑框范围就会取消编辑状态
    var sheetIframe = window.frameElement
    var ls = sheetIframe.contentWindow.luckysheet
    var lsjs = ls.toJson()
    // 取消原本功能：移除单元格取消编辑状态
    lsjs.hook.sheetMousemove = null

		document.addEventListener('keydown', function(event) {
			if (event.ctrlKey && event.keyCode === 83) { // keyCode 83 对应 'S'
				event.preventDefault();
				saveModelDefine();
			}
		});

		//  修正上下移动行时，如果某个格没有值，会被目标行的值覆盖
		if (lsjs?.hook?.cellUpdateBefore) {
      var originFuncStr = 'function (r,c,v,isRefresh) {\n                    //console.log("cellUpdateBefore",luckysheet.getSheet(), r, c, v, isRefresh)\n                    if(!checkUpdateBefore(luckysheet.getSheet().index, {row:[r,r],column:[c,c]})){\n                        return false;\n                    }\n                    return checkDataValidity(luckysheet.getSheet().index, {row:r,column:c},v);\n\n\n                }';
      if (lsjs?.hook?.cellUpdateBefore.toString() == originFuncStr) {
        lsjs.hook.cellUpdateBefore = function(row, column, value) {
						if (value instanceof Object) {
								// 当属性数量不等于1时，才检查 v 和 m
								if (Object.keys(value).length !== 1) {
										if (value.v === undefined) {
												value.v = null;
										}
										if (value.m === undefined) {
												value.m = null;
										}
								}
						}
						return checkDataValidity(luckysheet.getSheet().index, {row: row, column: column}, value);
				}
			} else if (lsjs?.hook?.cellUpdateBefore.toString().includes('setRangeMergeBefore')) {
				createAlert('表格方法 luckysheet.toJson().hook.cellUpdateBefore 版本有变动，请更新脚本代码', 'error')
				return
			}
		}
		//  修正点击某些单元格，增加了不需要的数据验证
		if (lsjs?.hook?.cellMousedown) {
      var originFuncStr = `function (cell,position,sheet) {\n                    //console.log(cell,position,sheet,luckysheet.getLuckysheetfile());\n                    $("#dictContainer").remove();\n                    $("#luckysheet-dataVerification-dropdown-List").hide();\n                    cur_cell = {c:position.c,r:position.r};\n                    var r = position.r+1;\n                    if(authType>0 && sheet.index=="columnsSheet" && position.r>=4) {\n                        /*if ([2, 3, 4].includes(position.c)) {\n                            if (luckysheet.getCellValue(position.r, position.c) == "□") {\n                                luckysheet.setCellValue(position.r, position.c, "?");\n                            } else {\n                                luckysheet.setCellValue(position.r, position.c, "□");\n                            }\n                        }*/\n                    }\n                    if(sheet.index=="columnsSheet" &&  cur_cell.r>=5 && cur_cell.c==9 && cell!=null && isNotEmpty(cell.v)){\n                        Array.from(document.getElementById('dictDataPage').contentWindow.dictList).forEach(function(item){\n                            if(item[0]==cell.v){\n                                $("#dictContainer").remove();\n                                var dictContainer = $('<div class="dictContainer" id="dictContainer"><span style="color:red">'+item[1]+'('+item[0]+')</span></div>');\n                                item[2].forEach(function(item2){\n                                    dictContainer.append('<div class="dictitem">'+item2[1]+'：'+item2[0]+'</div>')\n                                })\n                                dictContainer.offset({\n                                    left : $('#luckysheet-cell-selected').offset().left,\n                                    top : (parseFloat($('#luckysheet-cell-selected').offset().top)+parseFloat($('#luckysheet-cell-selected').height()))\n                                });\n                                container.append(dictContainer);\n                                dictContainer.on("mouseenter",function(e){\n                                    bShowdDictContainer  = true;\n                                }).on("mouseleave",function(e){\n                                    bShowdDictContainer  = false;\n                                });\n                                dictContainer.trigger("mouseenter")\n                                $("#luckysheet-dataVerification-dropdown-btn").on("click",function(e) {\n                                    dictContainer.remove();\n                                });\n                            }\n                        });\n                    }\n                    try {\n                        if (authType > 0 && cell.ht==undefined && sheet.dataVerification[position.r + "_"+position.c].type == "checkbox") {\n                            luckysheet.setCellFormat(position.r, position.c, "ht", 0)\n                        }\n                    }catch (e){}\n\n                    if(sheet.dataVerification!=undefined && sheet.dataVerification[position.r+"_0"]!=undefined){\n                        return true;\n                    }\n\n                    if(sheet.index=="columnsSheet" && r>=5){\n                        if(dictList.length==0){\n                            refreshDict();\n                        }\n\n                        if(authType>0){\n                            luckysheet.setDataVerification({ "type": "validity","type2":"personal", "value1": validKey,"prohibitInput": true   }, {range:"A"+r+":A"+r});\n                            luckysheet.setDataVerification({ "type": "dropdown", "value1": Object.keys(dataBaseType),   "prohibitInput": true   }, {range:"F"+r+":F"+r});\n                            luckysheet.setDataVerification({ "type": "number_integer","type2":"bw", "value1": "1", "value2": "99999", "prohibitInput": true   }, {range:"G"+r+":G"+r});\n                            luckysheet.setDataVerification({ "type": "number_integer","type2":"bw", "value1": "1", "value2": "12", "prohibitInput": true   }, {range:"H"+r+":H"+r});\n                            luckysheet.setDataVerification({ "type": "dropdown", "value1":dictList.length>0?dictList:"-",   "prohibitInput": true   }, {range:"J"+r+":J"+r});\n                        }\n                    }else if(sheet.index=="indexSheet" && r>=3 && authType>0){\n                        luckysheet.setDataVerification({ "type": "validity","type2":"personal", "value1": validKey,"prohibitInput": true   }, {range:"A"+r+":A"+r,order:sheet.order});\n                        luckysheet.setDataVerification({ "type": "dropdown", "value1": "模型!A5:A2000",   "prohibitInput": true   }, {range:"B"+r+":B"+r,order:sheet.order});\n                        luckysheet.setDataVerification({ "type": "dropdown", "value1": "ASC,DESC",   "prohibitInput": true   }, {range:"C"+r+":C"+r,order:sheet.order});\n                        //luckysheet.setDataVerification({ "type": "checkbox", "value1": true,"value2":false, "prohibitInput": true   }, {range:"D3:D"+sheet.data.length,order:sheet.order});\n                    }else if(sheet.index=="propertiesSheet" && r>=3){\n                        //luckysheet.setDataVerification({ "type": "validity","type2":"personal", "value1": validKey,"prohibitInput": true   }, {range:"A"+r+":A"+r,order:sheet.order});\n                    }\n                    //console.log(luckysheet.getSheet());\n                }`;
      if (lsjs?.hook?.cellMousedown.toString() == originFuncStr) {
        lsjs.hook.cellMousedown = function (cell, position, sheet) {
          //console.log(cell,position,sheet,luckysheet.getLuckysheetfile());
          $('#dictContainer').remove()
          $('#luckysheet-dataVerification-dropdown-List').hide()
          cur_cell = { c: position.c, r: position.r }
          var r = position.r + 1
          if (authType > 0 && sheet.index == 'columnsSheet' && position.r >= 4) {
          }
          if (
            sheet.index == 'columnsSheet' &&
            cur_cell.r >= 5 &&
            cur_cell.c == 9 &&
            cell != null &&
            isNotEmpty(cell.v)
          ) {
            Array.from(document.getElementById('dictDataPage').contentWindow.dictList).forEach(function (item) {
              if (item[0] == cell.v) {
                $('#dictContainer').remove()
                var dictContainer = $(
                  '<div class="dictContainer" id="dictContainer"><span style="color:red">' +
                    item[1] +
                    '(' +
                    item[0] +
                    ')</span></div>'
                )
                item[2].forEach(function (item2) {
                  dictContainer.append('<div class="dictitem">' + item2[1] + '：' + item2[0] + '</div>')
                })
                dictContainer.offset({
                  left: $('#luckysheet-cell-selected').offset().left,
                  top:
                    parseFloat($('#luckysheet-cell-selected').offset().top) +
                    parseFloat($('#luckysheet-cell-selected').height()),
                })
                container.append(dictContainer)
                dictContainer
                  .on('mouseenter', function (e) {
                    bShowdDictContainer = true
                  })
                  .on('mouseleave', function (e) {
                    bShowdDictContainer = false
                  })
                dictContainer.trigger('mouseenter')
                $('#luckysheet-dataVerification-dropdown-btn').on('click', function (e) {
                  dictContainer.remove()
                })
              }
            })
          }
          try {
            if (
              authType > 0 &&
              cell.ht == undefined &&
              sheet.dataVerification[position.r + '_' + position.c].type == 'checkbox'
            ) {
              luckysheet.setCellFormat(position.r, position.c, 'ht', 0)
            }
          } catch (e) {}

          if (sheet.dataVerification != undefined && sheet.dataVerification[position.r + '_0'] != undefined) {
            return true
          }

          if (sheet.index == 'columnsSheet' && r >= 5) {
            if (dictList.length == 0) {
              refreshDict()
            }

            if (authType > 0) {
              luckysheet.setDataVerification(
                { type: 'validity', type2: 'personal', value1: validKey, prohibitInput: true },
                { range: 'A' + r + ':A' + r }
              )
              luckysheet.setDataVerification(
                { type: 'dropdown', value1: Object.keys(dataBaseType), prohibitInput: true },
                { range: 'F' + r + ':F' + r }
              )
              luckysheet.setDataVerification(
                { type: 'number_integer', type2: 'bw', value1: '1', value2: '99999', prohibitInput: true },
                { range: 'G' + r + ':G' + r }
              )
              luckysheet.setDataVerification(
                { type: 'number_integer', type2: 'bw', value1: '1', value2: '100', prohibitInput: true },
                { range: 'H' + r + ':H' + r }
              )
              luckysheet.setDataVerification(
                { type: 'dropdown', value1: dictList.length > 0 ? dictList : '-', prohibitInput: true },
                { range: 'J' + r + ':J' + r }
              )
            }
          } else if (sheet.index == 'indexSheet' && r >= 3 && authType > 0) {
            luckysheet.setDataVerification(
              { type: 'validity', type2: 'personal', value1: validKey, prohibitInput: true },
              { range: 'A' + r + ':A' + r, order: sheet.order }
            )
            luckysheet.setDataVerification(
              { type: 'dropdown', value1: '模型!A5:A2000', prohibitInput: true },
              { range: 'B' + r + ':B' + r, order: sheet.order }
            )
            luckysheet.setDataVerification(
              { type: 'dropdown', value1: 'ASC,DESC', prohibitInput: true },
              { range: 'C' + r + ':C' + r, order: sheet.order }
            )
          } else if (sheet.index == 'propertiesSheet' && r >= 3) {
          }
        }
      } else if (lsjs?.hook?.cellMousedown.toString().includes(`value1: '1', value2: '12'`)) {
        createAlert('表格方法 luckysheet.toJson().hook.cellMousedown 版本有变动，请更新脚本代码', 'error')
        return
      }
		}
		//  去除输入字段自动弹出联想词
		if (lsjs?.hook?.cellKeyup) {
      var originFuncStr = `function (index,range,value,kcode,event){   //匹配词库\n                    //console.log(index,range,value,kcode,event)\n                    $("#dictContainer").remove();\n                    if(index=="columnsSheet"){\n                        var r = range[0];\n                        var c = range[1];\n                        if(r>=4 && c<=1) {\n                            if ((event.key != "Process" && value.length >= 2) || (event.key == "Process" && event.originalEvent.code == "Space")) {\n                                var colnum = 0;\n                                if (c == 0) colnum = 1; //第一列中字段代码\n                                //wordSheetData = document.getElementById('wordStorePage').contentWindow.wordSheetData;\n                                window.parent.postMessage({\n                                    type: "searchKeyword",\n                                    cell: range,\n                                    index: colnum,\n                                    keyWord: value\n                                }, '/')\n                            }\n                        }\n                        if(r>4 && c==9) {\n                            if (dictList.length > 0 && isNotEmpty(value)) {\n                                var optionHtml = "";\n                                dictList.forEach(option => {\n                                    //console.log(option)\n                                    if(option[1].includes(value)){\n                                        optionHtml += ('<div class="dropdown-List-item luckysheet-mousedown-cancel" value="'+option[0]+'">'+option[1]+'</div>');\n                                    }\n                                })\n                                $("#luckysheet-dataVerification-dropdown-List").html(optionHtml)\n                            }\n                        }\n                    }\n                    //return checkUpdateBefore(luckysheet.getSheet().index, range[0]);\n                }`;
      if (lsjs?.hook?.cellKeyup.toString() == originFuncStr) {
        lsjs.hook.cellKeyup = function (index,range,value,kcode,event){
          $("#dictContainer").remove();
          if(index=="columnsSheet"){
              var r = range[0];
              var c = range[1];
              if(r>4 && c==9) {
                  if (dictList.length > 0 && isNotEmpty(value)) {
                      var optionHtml = "";
                      dictList.forEach(option => {
                          if(option[1].includes(value)){
                              optionHtml += ('<div class="dropdown-List-item luckysheet-mousedown-cancel" value="'+option[0]+'">'+option[1]+'</div>');
                          }
                      })
                      $("#luckysheet-dataVerification-dropdown-List").html(optionHtml)
                  }
              }
          }
        }
			} else if (lsjs?.hook?.cellKeyup.toString().includes('r>=4 && c<=1')) {
				createAlert('表格方法 luckysheet.toJson().hook.cellKeyup 版本有变动，请更新脚本代码', 'error')
				return
			}
		}

    // 移除表格区域，主动取消编辑状态
    document.querySelector('#modelDefineSheet').parentElement.addEventListener('mouseleave', function (e) {
      var inputBox = document.querySelector('#luckysheet-input-box')
      if (
        parseInt($('#luckysheet-input-box').css('top')) > 0 &&
        e.toElement != inputBox &&
        !inputBox.contains(e.toElement)
      )
        ls.exitEditMode()
    })
    // ----------------------------------------- 搜索词库
    var searchKeywordsDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="搜索词库" id="luckysheet-icon-tranEngCase" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-kuandu" style="user-select: none;font-size: 14px; color:#000000">词</div> </div> </div> </div> </div>'
    )
    bindToolTip(searchKeywordsDiv);
    searchKeywordsDiv.addEventListener('click', function () {
      var sheetIframe = window.frameElement
      var ls = sheetIframe.contentWindow.luckysheet

      // 假设wordSheetData已经在外部定义并赋值
      var keywords = []
      let wordSheetData = sheetIframe.contentWindow.document.getElementById('wordStorePage').contentWindow.wordSheetData
      if (wordSheetData.length > 0) {
        for (let sheet of wordSheetData) {
          for (let row of sheet.data) {
            if (sheet.data.indexOf(row) === 0) continue // 跳过表头
            let datarow = [row[2] ? row[2].m : ''] // 第2列是关键词
            for (let col of row) {
              if (col && col !== row[2]) {
                datarow.push(col.m)
              }
            }
            keywords.push(datarow)
          }
        }
      }
      function showkeywords(keyword) {
        if (keywords.length > 0) {
          $('#changeLog', window.parent.document)[0].style.display = 'none'
          var wordDiv = $('#wordDiv', window.parent.document)
          wordDiv.empty()

          var no = 1
          for (let row of keywords) {
            if (!row[0]) continue // 跳过空行
            if (
              keyword == '' ||
              (keyword != '' &&
                ((row[0] || '').includes(keyword.toLowerCase()) ||
                  (row[2] || '').includes(keyword.toLowerCase()) ||
                  (row[3] || '').includes(keyword.toLowerCase())))
            ) {
              wordDiv.append(
                "<li class='logtime word'>" +
                  "<span class='log wordName'>" +
                  row[0] +
                  '</span><br>' +
                  "<span class='wordInfo'>" +
                  row.slice(2, -2).join(' ') +
                  '</span></li>'
              )
              no++
              if (no >= 100) break
            }
          }

          if ($('.word', wordDiv).length === 0) {
            wordDiv.append("<li class='logtime'><span class='log'>无匹配词库</span></li>")
          } else {
            $('.wordName', wordDiv).click(function () {
              copyRichText($(this).text())
              createAlert(`已复制 ${$(this).text()}`, 'success')
            })
          }

          if (wordDiv[0].style.display !== 'block') {
            wordDiv[0].style.display = 'block'
          }
        }
      }

      var keyword = prompt('请输入搜索词库的关键词：', '')
      if (keyword) {
        showkeywords(keyword)
      } else {
        createAlert('未输入关键词', 'error')
      }
    })
    // ----------------------------------------- 转换所选区域驼峰<=>下划线
    var tranCamelCaseDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="所选区域驼峰<=>下划线" id="luckysheet-icon-tranEngCase" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-kuandu" style="user-select: none;font-size: 14px; color:#FF8000">_a</div> </div> </div> </div> </div>'
    )
    bindToolTip(tranCamelCaseDiv);
    tranCamelCaseDiv.addEventListener('click', function () {
      var sheetIframe = window.frameElement
      var ls = sheetIframe.contentWindow.luckysheet
      var currSheet = ls.getSheet()
      if (currSheet) {
        tranEngCamelCaseRange(ls, null)
        createAlert('已转换驼峰/下划线', 'success')
      }
    })

    // ----------------------------------------- 转换表、字段大小写
    var tranEngCaseDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="转换表、字段大小写" id="luckysheet-icon-tranEngCase" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-kuandu" style="user-select: none;font-size: 14px; color:#FF8000">Aa</div> </div> </div> </div> </div>'
    )
    bindToolTip(tranEngCaseDiv);
    tranEngCaseDiv.addEventListener('click', function () {
      var sheetIframe = window.frameElement
      var ls = sheetIframe.contentWindow.luckysheet
      var currSheet = ls.getSheet()
      if (currSheet) {
        tranEngCaseRange(ls, null)
        createAlert('已转换大小写', 'success')
      }
      /* 按照模型的表和字段
      if (currSheet) {
        const rowCnt = ls.toJson().data[0].row
        const columnCnt = ls.toJson().data[0].column

        tranEngCaseRange(ls, { row: [0, 0], column: [1, 1] })
        tranEngCaseRange(ls, { row: [4, rowCnt - 1], column: [0, 0] })

      }*/
    })

    // ----------------------------------------- 调整字体
    var ajstFontDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="调整字体大小样式,删除无用字段行" id="luckysheet-icon-fontformat" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-ziti" style="user-select: none;font-size: 14px; color:#00BFFF">样</div> </div> </div> </div> </div>'
    )
    bindToolTip(ajstFontDiv);
    ajstFontDiv.addEventListener('click', async function () {
      var msg = ''
      var sheetIframe = window.frameElement
      var ls = sheetIframe.contentWindow.luckysheet

      if (ls.toJson().data.length === 3) {
        const currSheet = ls.getSheet()

        // ======================== 处理sheet样式，由于sheetapi有问题，只能更新当页数据，不能更新跨页，所以需要每个页面自己点处理 ========================
        // ============ 处理模型sheet ============
        if(currSheet.order == 0){
          const rowCnt0 = ls.toJson().data[0].row
          const columnCnt0 = ls.toJson().data[0].column
          ls.setColumnWidth({0: 230, 1: 230, 2: 70, 3: 60, 4: 73, 5: 80, 6: 70, 7: 69, 8: 350, 9: 232}, {order: 0})
          // 第一行除功能码；第二行以下。字体、字体大小、水平居左，垂直居中
          ls.setRangeFormat('ff', 2, {
            range: [
              { row: [4, rowCnt0 - 1], column: [0, 1] },
              { row: [4, rowCnt0 - 1], column: [5, columnCnt0 - 1] },
            ],
            order: 0
          })
          ls.setRangeFormat('fs', 11, {
            range: [
              { row: [4, rowCnt0 - 1], column: [0, 1] },
              { row: [4, rowCnt0 - 1], column: [5, columnCnt0 - 1] },
            ],
            order: 0
          })
          ls.setRangeFormat('vt', 0, {
            range: [
              { row: [4, rowCnt0 - 1], column: [0, 1] },
              { row: [4, rowCnt0 - 1], column: [5, columnCnt0 - 1] },
            ],
            order: 0
          })
          ls.setRangeFormat('ht', 1, {
            range: [
              { row: [4, rowCnt0 - 1], column: [0, 1] },
              { row: [4, rowCnt0 - 1], column: [5, columnCnt0 - 1] },
            ],
            order: 0
          })
          // 调整边框似乎无效
          ls.setRangeFormat(
            'bd',
            { borderType: 'border-none' },
            {
              range: [
                { row: [4, rowCnt0 - 1], column: [0, 1] },
                { row: [4, rowCnt0 - 1], column: [5, columnCnt0 - 1] },
              ],
              order: 0
            }
          )
          // 调整主键、非空、数据类型等表格对齐样式
          ls.setRangeFormat('vt', 0, {
            range: [{ row: [0, rowCnt0 - 1], column: [2, 7] }],
            order: 0
          })
          ls.setRangeFormat('ht', 0, {
            range: [{ row: [0, rowCnt0 - 1], column: [2, 7] }],
            order: 0
          })

          // 头部四行全部居中, 除名称代码，只能一个个改格式
          var topCells = ls.getRangeWithFlatten([
            { row: [0, 3], column: [0, 0] },
            { row: [3, 3], column: [0, columnCnt0 - 1] },
            { row: [0, 3], column: [2, columnCnt0 - 1] },
          ])

          topCells.forEach((c) => {
            ls.setCellFormat(c.r, c.c, 'ff', 2, {order : 0})
            ls.setCellFormat(c.r, c.c, 'vt', 0, {order : 0})
            ls.setCellFormat(c.r, c.c, 'ht', 0, {order : 0})
          })

          // 业务说明居左
          ls.setCellFormat(2, 1, 'ff', 2, {order : 0})
          ls.setCellFormat(2, 1, 'fs', 10, {order : 0})
          ls.setCellFormat(2, 1, 'vt', 0, {order : 0})
          ls.setCellFormat(2, 1, 'ht', 1, {order : 0})

          // 模型代码、模型名称
          ls.setCellFormat(0, 1, 'ff', 2, {order : 0})
          ls.setCellFormat(0, 1, 'fs', 11, {order : 0})
          ls.setCellFormat(0, 1, 'vt', 0, {order : 0})
          ls.setCellFormat(0, 1, 'ht', 0, {order : 0})

          ls.setCellFormat(1, 1, 'ff', 2, {order : 0})
          ls.setCellFormat(1, 1, 'fs', 11, {order : 0})
          ls.setCellFormat(1, 1, 'vt', 0, {order : 0})
          ls.setCellFormat(1, 1, 'ht', 0, {order : 0})
        }
        // ============ 处理索引sheet ============
        if(currSheet.order == 1){
          const rowCnt1 = ls.toJson().data[1].row
          const columnCnt1 = ls.toJson().data[1].column
          ls.setColumnWidth({0: 230, 1: 230, 2: 70, 3: 60, 4: 381, 5: 80, 6: 70, 7: 69, 8: 350, 9: 232}, {order: 1})
          ls.setRangeFormat('ff', 2, {
            range: [
              { row: [0, rowCnt1 - 1], column: [0, columnCnt1 - 1] },
            ],
            order: 1
          })
          ls.setRangeFormat('fs', 11, {
            range: [
              { row: [0, rowCnt1 - 1], column: [0, columnCnt1 - 1] },
            ],
            order: 1
          })
          ls.setRangeFormat('vt', 0, {
            range: [
              { row: [0, rowCnt1 - 1], column: [0, columnCnt1 - 1] },
            ],
            order: 1
          })
          ls.setRangeFormat('ht', 0, {
            range: [
              { row: [0, rowCnt1 - 1], column: [0, columnCnt1 - 1] },
            ],
            order: 1
          })
        }

        // ============ 处理属性sheet ============
        if(currSheet.order == 2){
          const rowCnt2 = ls.toJson().data[2].row
          const columnCnt2 = ls.toJson().data[2].column
          ls.setColumnWidth({0: 230, 1: 381, 2: 70, 3: 60, 4: 73, 5: 80, 6: 70, 7: 69, 8: 350, 9: 232}, {order: 2})
          ls.setRangeFormat('ff', 2, {
            range: [
              { row: [0, rowCnt2 - 1], column: [0, columnCnt2 - 1] },
            ],
            order: 2
          })
          ls.setRangeFormat('fs', 11, {
            range: [
              { row: [0, rowCnt2 - 1], column: [0, columnCnt2 - 1] },
            ],
            order: 2
          })
          ls.setRangeFormat('vt', 0, {
            range: [
              { row: [0, rowCnt2 - 1], column: [0, columnCnt2 - 1] },
            ],
            order: 2
          })
          ls.setRangeFormat('ht', 0, {
            range: [
              { row: [0, rowCnt2 - 1], column: [0, columnCnt2 - 1] },
            ],
            order: 2
          })
        }

        msg += '已调整字体'

        // 删除无用字段行
        let noValidRow0 = [], noValidRow1 = [], noValidRow2 = []

        // 收集字段代码为空的行,从大到小删除，就不会受每次删除后大的行号变化的影响
        function findNoValidRow(ls, sheetOrder){
          const sheetData = ls.toJson().data[sheetOrder].data
          const sheetRowCnt = ls.toJson().data[sheetOrder].row
          var res = [];
          for (var i = sheetOrder == 0 ? 4 : 0; i < sheetRowCnt; i++) {
            // 每行的第一列、第二列都为空则 改行为无效行
            if ((sheetData[i][0] == null || sheetData[i][0]?.v == undefined || sheetData[i][0]?.v.trim() === '')
                  && (sheetData[i][1] == null || sheetData[i][1]?.v == undefined || sheetData[i][1]?.v.trim() === '')) {
              res.push(i)
            }
          }
          return res;
        }
        noValidRow0 = findNoValidRow(ls, currSheet.order);

        // 任意一个页签有多余行，则提示
        if (noValidRow0.length > 0) {
          function deleteNoValidRowAndUpdateSheetByIndex(ls, order, noValidRow) {

            noValidRow.sort((a, b) => b - a)
            noValidRow.forEach((row) => {
              ls.deleteRow(row, row, order)
            })

            const jsonData = ls.toJson().data;
            // 拷贝原始数据，防止直接修改原数据
            const targetSheet = { ...jsonData[order] };

            // 更新逻辑
            targetSheet.row = targetSheet.row - noValidRow.length;
            targetSheet.data = targetSheet.data.slice(0, targetSheet.row);

            // 组装新数据
            const updatedData = [
              ...jsonData.slice(0, order),
              targetSheet,
              ...jsonData.slice(order + 1),
            ];

            // 提交更新
            ls.updataSheet({ data: updatedData });
          }

          if(currSheet.order == 2){
            // 表属性页面就直接删多余行
            deleteNoValidRowAndUpdateSheetByIndex(ls, currSheet.order, noValidRow0)
            msg += `, 且删除了无效行`
          }else{
						// 直接删除无效行，不提示了
						deleteNoValidRowAndUpdateSheetByIndex(ls, currSheet.order, noValidRow0)
						msg += `, 且删除了无效行`
						/*
            const result = await Swal.fire({
              title: '提示',
              html: `<span class="swal2-content">发现无效行，要删除这些行吗？<br/>
                行数:${noValidRow0.sort((a, b) => a - b).map((v) => v + 1)}
                </span>`,
              showCloseButton: false,
              showConfirmButton: true,
              confirmButtonText: '确认',
              showCancelButton: true,
              cancelButtonText: '取消',
              icon: 'warning',
            });
            if (result.isConfirmed) {
              deleteNoValidRowAndUpdateSheetByIndex(ls, currSheet.order, noValidRow0)
              msg += `, 且删除了无效行`
            } else if (result.dismiss === Swal.DismissReason.cancel) {
              msg += `, 未删除无效行`
            }*/
          }
          createAlert(msg, 'success', 1500)
        }
      }else{
        createAlert('模型脚本需更新：未识别到三个sheet(模型、索引、属性)', 'error')
      }
    })

    // ----------------------------------------- 复制文档截图
    var copyScreenShotDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="复制文档截图"  id="luckysheet-icon-fontformat" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-ziti" style="user-select: none;font-size: 14px; color:green">图</div> </div> </div> </div> </div>'
    )
    bindToolTip(copyScreenShotDiv);
    copyScreenShotDiv.addEventListener('click', async function () {

      const sheetIframe = window.frameElement;
      const ls = sheetIframe.contentWindow.luckysheet;
      const sheetData = ls.toJson().data[0];
      const rowCnt = sheetData.row;  // 总行数
      const columnCnt = sheetData.column;  // 总列数

      // 确认是哪种方式
      Swal.fire({
        title: `请选择截图范围`,
        icon: 'warning',
        showConfirmButton: true,
        confirmButtonText: '全部',
        showCancelButton: true,
        cancelButtonText: '取消',
        showDenyButton: true,
        denyButtonText: '选区',
      }).then((result) => {
        if (result.isConfirmed) {
          var allRange = {range:{row:[0,rowCnt-1],column:[0,columnCnt-1]}};
          var altText = getRangeText(ls, allRange);
          copyRichText(luckysheet.getScreenshot(allRange), {type:'image',altText} );
          createAlert('已复制截图', 'success', 2000)
        } else if (result.isDenied) {
          var altText = getRangeText(ls);
          copyRichText(luckysheet.getScreenshot(), {type:'image',altText});
          createAlert('已复制选区截图', 'success', 2000)
        }
      });
    });

    // ----------------------------------------- 上移动表字段
    var upColDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="上移字段" id="luckysheet-icon-tranEngCase" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-shengxu1" style="user-select: none;font-size: 30px; color:black">↑</div> </div> </div> </div> </div>'
    )
    bindToolTip(upColDiv);
    upColDiv.addEventListener('click', function () {
      var sheetIframe = window.frameElement
      var ls = sheetIframe.contentWindow.luckysheet
      moveFieldRow(ls, 'up')
    })
    // ----------------------------------------- 下移动表字段
    var downColDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="下移字段" id="luckysheet-icon-tranEngCase" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-jiangxu1" style="user-select: none;font-size: 30px; color:black">↓</div> </div> </div> </div> </div>'
    )
    bindToolTip(downColDiv);
    downColDiv.addEventListener('click', function () {
      var sheetIframe = window.frameElement
      var ls = sheetIframe.contentWindow.luckysheet
      moveFieldRow(ls, 'down')
    })
    // ----------------------------------------- 置顶表字段
    var topColDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="置顶字段" id="luckysheet-icon-tranEngCase" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-dingbuduiqi" style="user-select: none;font-size: 30px; color:black"></div> </div> </div> </div> </div>'
    )
    bindToolTip(topColDiv);
    topColDiv.addEventListener('click', function () {
      var sheetIframe = window.frameElement
      var ls = sheetIframe.contentWindow.luckysheet
      moveFieldRow(ls, 'top')
    })
    // ----------------------------------------- 置底表字段
    var bottomColDiv = createDivByHtml(
      '<div class="luckysheet-toolbar-button luckysheet-inline-block " data-tooltip="置底字段" id="luckysheet-icon-tranEngCase" role="button" style="user-select: none;"><div class="luckysheet-toolbar-button-outer-box luckysheet-inline-block" style="user-select: none;"> <div class="luckysheet-toolbar-button-inner-box luckysheet-inline-block" style="user-select: none;">  <div class="luckysheet-icon luckysheet-inline-block " style="user-select: none;">  <div aria-hidden="true" class="luckysheet-icon-img-container luckysheet-icon-img iconfont luckysheet-iconfont-dibuduiqi" style="user-select: none;font-size: 30px; color:black">↑</div> </div> </div> </div> </div>'
    )
    bindToolTip(bottomColDiv);
    bottomColDiv.addEventListener('click', function () {
      var sheetIframe = window.frameElement
      var ls = sheetIframe.contentWindow.luckysheet
      moveFieldRow(ls, 'bottom')
    })

    waEditor.firstChild.nextElementSibling.nextElementSibling.setAttribute('data-tooltip', '保存')
    bindToolTip(waEditor.firstChild.nextElementSibling.nextElementSibling);
    waEditor.insertBefore(sepDiv3, waEditor.firstChild.nextElementSibling.nextElementSibling.nextElementSibling)

    waEditor.insertBefore(upColDiv, sepDiv3)
    waEditor.insertBefore(downColDiv, sepDiv3)
    waEditor.insertBefore(topColDiv, sepDiv3)
    waEditor.insertBefore(bottomColDiv, sepDiv3)
    waEditor.insertBefore(bottomColDiv, sepDiv3)

    waEditor.insertBefore(sepDiv2, upColDiv)
    waEditor.insertBefore(searchKeywordsDiv, sepDiv2)
    waEditor.insertBefore(tranCamelCaseDiv, sepDiv2)
    waEditor.insertBefore(tranEngCaseDiv, sepDiv2)
    waEditor.insertBefore(ajstFontDiv, sepDiv2)
    waEditor.insertBefore(copyScreenShotDiv, sepDiv2)
    waEditor.insertBefore(sepDiv, searchKeywordsDiv)
  })

  GM_addStyle(`
 /* 优化表格里的字体 */
 body{
    font-family: inherit;
 }
 /* 优化接口说明样式 */
 .w-e-text-container [data-slate-editor] {
  padding: 0px 10px 20px 10px !important;
}
#changeTime{
  font-family: monospace, Verdana, Arial, Helvetica, AppleGothic, sans-serif !important;
}
/* 搜索词列表样式 */
.word {
    cursor: auto !important;
}
.log.wordName {
    cursor: pointer;
}
	/* 数据类型下拉滚动条 */
#luckysheet-dataVerification-dropdown-List::-webkit-scrollbar {
    width: 6px; /* 设置滚动条的宽度 */
    height: 6px; /* 设置滚动条的高度 */
}
/* 滚动条轨道 */
#luckysheet-dataVerification-dropdown-List::-webkit-scrollbar-track {
    background-color: #f0f0f0; /* 设置滚动条轨道的颜色 */
}

/* 滚动条滑块 */
#luckysheet-dataVerification-dropdown-List::-webkit-scrollbar-thumb {
    background-color: #888; /* 设置滚动条滑块的颜色 */
    border-radius: 10px; /* 设置滚动条滑块的圆角 */
}

/* 滚动条滑块悬停效果 */
#luckysheet-dataVerification-dropdown-List::-webkit-scrollbar-thumb:hover {
    background-color: #555; /* 设置滚动条滑块悬停时的颜色 */
}

/* 针对Firefox的自定义 */
#luckysheet-dataVerification-dropdown-List {
    scrollbar-color: #888 #f0f0f0; /* 第一个参数是滑块颜色，第二个参数是轨道颜色 */
    scrollbar-width: thin; /* 设置滚动条的宽度为细 */
		min-width: fit-content !important;

		border-radius: 5px;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
/* 某字典项弹窗滚动条 */
#dictContainer::-webkit-scrollbar {
    width: 6px; /* 设置滚动条的宽度 */
    height: 6px; /* 设置滚动条的高度 */
}
/* 滚动条轨道 */
#dictContainer::-webkit-scrollbar-track {
    background-color: #f0f0f0; /* 设置滚动条轨道的颜色 */
}

/* 滚动条滑块 */
#dictContainer::-webkit-scrollbar-thumb {
    background-color: #888; /* 设置滚动条滑块的颜色 */
    border-radius: 10px; /* 设置滚动条滑块的圆角 */
}

/* 滚动条滑块悬停效果 */
#dictContainer::-webkit-scrollbar-thumb:hover {
    background-color: #555; /* 设置滚动条滑块悬停时的颜色 */
}

/* 针对Firefox的自定义 */
#dictContainer {
    scrollbar-color: #888 #f0f0f0; /* 第一个参数是滑块颜色，第二个参数是轨道颜色 */
    scrollbar-width: thin; /* 设置滚动条的宽度为细 */
		min-width: fit-content !important;

		border: none;
		background: white !important; /* 背景颜色 */
		border-radius: 5px;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
.w-e-image-container > img{
	border-radius: 0.3125em;box-shadow: 0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.08);overflow: inherit !important;
}
.w-e-text-container [data-slate-editor] .w-e-selected-image-container {
	overflow: visible !important;
}
.w-e-text-container [data-slate-editor] code{
	color: #1E7AC3;
	background-color: rgba(0,0,0,0.03);
	border: 1px solid #f0f0f0;
	border-radius: 2px;
}
.w-e-text-container [data-slate-editor] code span{
	font-family: Verdana !important;
}
.w-e-text-container [data-slate-editor] pre>code{
	background-color: rgba(0,0,0,0.03);
	border: 1px solid #f0f0f0;
	border-radius: 2px;
}
  `)
}

/* 优化monaco编辑器
 * 1. 取消最下方的空白行
 * 2. 显示空白格
 */
function perfMonacoEditor() {
  // 找到 数据库代码页签，数据库脚本元素
  elmGetter.each('div#sqlScript.active', document, (sqlScript) => {
    let _monaco = ''
/*
    // 重构 template 方法，增加 modelDataSource
    var modelDataSource = sessionStorage.getItem('modelDataSource')
    var modelDataType = sessionStorage.getItem('modelDataType')

    var s = {
        append: {
          start: "'+(",
          end: ")+'",
          startencode: "'+encodeHTML(",
        },
        split: {
          start: "';out+=(",
          end: ");out+='",
          startencode: "';out+=encodeHTML(",
        },
      },
      p = /$^/
    function l(e) {
      return e.replace(/\\('|\\)/g, '$1').replace(/[\r\t\n]/g, ' ')
    }

    var oldDotTemplateStr = `function(e,n,t){var r,o,a=(n=n||d.templateSettings).append?s.append:s.split,c=0,i=n.use||n.define?function r(o,e,a){return("string"==typeof e?e:e.toString()).replace(o.define||p,function(e,r,n,t){return 0===r.indexOf("def.")&&(r=r.substring(4)),r in a||(":"===n?(o.defineParams&&t.replace(o.defineParams,function(e,n,t){a[r]={arg:n,text:t}}),r in a||(a[r]=t)):new Function("def","def['"+r+"']="+t)(a)),""}).replace(o.use||p,function(e,n){o.useParams&&(n=n.replace(o.useParams,function(e,n,t,r){if(a[t]&&a[t].arg&&r){var o=(t+":"+r).replace(/'|\\\\/g,"_");return a.__exp=a.__exp||{},a.__exp[o]=a[t].text.replace(new RegExp("(^|[^\\\\w$])"+a[t].arg+"([^\\\\w$])","g"),"$1"+r+"$2"),n+"def.__exp['"+o+"']"}}));var t=new Function("def","return "+n)(a);return t?r(o,t,a):t})}(n,e,t||{}):e;i=("var out='"+(n.strip?i.replace(/(^|\\r|\\n)\\t* +| +\\t*(\\r|\\n|$)/g," ").replace(/\\r|\\n|\\t|\\/\\*[\\s\\S]*?\\*\\//g,""):i).replace(/'|\\\\/g,"\\\\$&").replace(n.interpolate||p,function(e,n){return a.start+l(n)+a.end}).replace(n.encode||p,function(e,n){return r=!0,a.startencode+l(n)+a.end}).replace(n.conditional||p,function(e,n,t){return n?t?"';}else if("+l(t)+"){out+='":"';}else{out+='":t?"';if("+l(t)+"){out+='":"';}out+='"}).replace(n.iterate||p,function(e,n,t,r){return n?(c+=1,o=r||"i"+c,n=l(n),"';var arr"+c+"="+n+";if(arr"+c+"){var "+t+","+o+"=-1,l"+c+"=arr"+c+".length-1;while("+o+"<l"+c+"){"+t+"=arr"+c+"["+o+"+=1];out+='"):"';} } out+='"}).replace(n.evaluate||p,function(e,n){return"';"+l(n)+"out+='"})+"';return out;").replace(/\\n/g,"\\\\n").replace(/\\t/g,"\\\\t").replace(/\\r/g,"\\\\r").replace(/(\\s|;|\\}|^|\\{)out\\+='';/g,"$1").replace(/\\+''/g,""),r&&(n.selfcontained||!u||u._encodeHTML||(u._encodeHTML=d.encodeHTMLSource(n.doNotSkipEncoded)),i="var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : ("+d.encodeHTMLSource.toString()+"("+(n.doNotSkipEncoded||"")+"));"+i);try{return new Function(n.varname,i)}catch(e){throw"undefined"!=typeof console&&console.log("Could not create a template function: "+i),e}}`

    if (oldDotTemplateStr === doT.template.toString()) {
      doT.template = function (e, n, t) {
        var r,
          o,
          a = (n = n || d.templateSettings).append ? s.append : s.split,
          c = 0,
          i =
            n.use || n.define
              ? (function r(o, e, a) {
                  return ('string' == typeof e ? e : e.toString())
                    .replace(o.define || p, function (e, r, n, t) {
                      return (
                        0 === r.indexOf('def.') && (r = r.substring(4)),
                        r in a ||
                          (':' === n
                            ? (o.defineParams &&
                                t.replace(o.defineParams, function (e, n, t) {
                                  a[r] = {
                                    arg: n,
                                    text: t,
                                  }
                                }),
                              r in a || (a[r] = t))
                            : new Function('def', "def['" + r + "']=" + t)(a)),
                        ''
                      )
                    })
                    .replace(o.use || p, function (e, n) {
                      o.useParams &&
                        (n = n.replace(o.useParams, function (e, n, t, r) {
                          if (a[t] && a[t].arg && r) {
                            var o = (t + ':' + r).replace(/'|\\/g, '_')
                            return (
                              (a.__exp = a.__exp || {}),
                              (a.__exp[o] = a[t].text.replace(
                                new RegExp('(^|[^\\w$])' + a[t].arg + '([^\\w$])', 'g'),
                                '$1' + r + '$2'
                              )),
                              n + "def.__exp['" + o + "']"
                            )
                          }
                        }))
                      var t = new Function('def', 'return ' + n)(a)
                      return t ? r(o, t, a) : t
                    })
                })(n, e, t || {})
              : e
        ;(i = (
          "var out='" +
          (n.strip ? i.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g, ' ').replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g, '') : i)
            .replace(/'|\\/g, '\\$&')
            .replace(n.interpolate || p, function (e, n) {
              return a.start + l(n) + a.end
            })
            .replace(n.encode || p, function (e, n) {
              return (r = !0), a.startencode + l(n) + a.end
            })
            .replace(n.conditional || p, function (e, n, t) {
              return n
                ? t
                  ? "';}else if(" + l(t) + "){out+='"
                  : "';}else{out+='"
                : t
                ? "';if(" + l(t) + "){out+='"
                : "';}out+='"
            })
            .replace(n.iterate || p, function (e, n, t, r) {
              return n
                ? ((c += 1),
                  (o = r || 'i' + c),
                  (n = l(n)),
                  "';var arr" +
                    c +
                    '=' +
                    n +
                    ';if(arr' +
                    c +
                    '){var ' +
                    t +
                    ',' +
                    o +
                    '=-1,l' +
                    c +
                    '=arr' +
                    c +
                    '.length-1;while(' +
                    o +
                    '<l' +
                    c +
                    '){' +
                    t +
                    '=arr' +
                    c +
                    '[' +
                    o +
                    "+=1];out+='")
                : "';} } out+='"
            })
            .replace(n.evaluate || p, function (e, n) {
              return "';" + l(n) + "out+='"
            }) +
          "';return out;"
        )
          .replace(/\n/g, '\\n')
          .replace(/\t/g, '\\t')
          .replace(/\r/g, '\\r')
          .replace(/(\s|;|\}|^|\{)out\+='';/g, '$1')
          .replace(/\+''/g, '')),
          r &&
            (n.selfcontained || !u || u._encodeHTML || (u._encodeHTML = d.encodeHTMLSource(n.doNotSkipEncoded)),
            (i =
              "var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : (" +
              d.encodeHTMLSource.toString() +
              '(' +
              (n.doNotSkipEncoded || '') +
              '));' +
              i))
        try {
          i =
            'if(it) {it.dataSource =' +
            sessionStorage.getItem('modelDataSource') +
            ' || {};\n' +
            ' it.dataSource.dataType =' +
            sessionStorage.getItem('modelDataType') +
            ';}\n' +
            'it.func.translateField = function(colDataType){return it.dataSource?.dataType?.DATA?.ElasticSearch?.DATATYPE[colDataType] ? it.dataSource.dataType.DATA.ElasticSearch.DATATYPE[colDataType] : colDataType}\n' +
            i
          return new Function(n.varname, i)
        } catch (e) {
          throw ('undefined' != typeof console && console.log('Could not create a template function: ' + i), e)
        }
      }
    } else {
      createAlert('网站函数 doT.template 有更新，请更新对应脚本内容', 'warning')
    }*/

    // 定义Getter和Setter方法
    Object.defineProperty(this, 'monaco', {
      get: function () {
        return _monaco
      },
      set: function (value) {
        _monaco = value
        console.log('监控到 monaco 发生了改变')
        // 执行其他操作
        if (_monaco) {
					_monaco.editor.setTheme('vs-dark');

					setTimeout(()=>{
						// 获取所有 Monaco 编辑器实例
						const editors = monaco.editor.getEditors();
						// 遍历并更新每个编辑器的样式
						editors.forEach(editor => {
							editor.updateOptions({
								lineHeight: 20,
								scrollBeyondLastLine: false,
								renderWhitespace: true,
								renderControlCharacters: true,
								renderLineHighlight: 'all',
								renderFinalNewline: true,
								lineHeight: 20,
								wordWrap: 'on',
							});
						});
					},500);

        }
      },
    })

    // 新增按钮，设置默认选中数据库类型
    var dbSec = document.querySelector('#DBType');
    if(dbSec){
      var setDeftDbTypeBtn = document.querySelector('#setDeftDbType');
      if(!setDeftDbTypeBtn){
        var setDeftDbTypeDiv = createDivByHtml(
          `<button type="button" id="setDeftDbType" style="font-size: 100%;color:orange;">设为默认数据库</button>`
        );
        setDeftDbTypeDiv.addEventListener('click', function () {
          sessionStorage.setItem('defaultDbType', dbSec.value);
          createAlert(`已将“${dbSec.value}”设为默认数据库`, 'success', 1500);
        });
        dbSec.parentElement.appendChild(setDeftDbTypeDiv);
      }
      var defaultDbType = sessionStorage.getItem('defaultDbType');
      if(defaultDbType){
        dbSec.value = defaultDbType;
        const changeEvent = new Event('change');
        dbSec.dispatchEvent(changeEvent);
      }
    }
  });

  // 模型的程序代码页签
  elmGetter.each('div#codeScript.active', document, (codeScript) => {

    let _monaco = ''
		// 定义Getter和Setter方法
		Object.defineProperty(this, 'monaco', {
      get: function () {
        return _monaco
			},
      set: function (value) {
        _monaco = value
        console.log('监控到 monaco 发生了改变')
        // 执行其他操作
				if (_monaco) {
					_monaco.editor.setTheme('vs-dark');

					setTimeout(()=>{
						// 获取所有 Monaco 编辑器实例
						const editors = monaco.editor.getEditors();
						// 遍历并更新每个编辑器的样式
						editors.forEach(editor => {
							editor.updateOptions({
								lineHeight: 20,
								scrollBeyondLastLine: false,
								renderWhitespace: true,
								renderControlCharacters: true,
								renderLineHighlight: 'all',
								renderFinalNewline: true,
								lineHeight: 20,
								wordWrap: 'on',
							});
						});
					},500);


        }
      },
    })

    // 新增按钮，设置默认选中数据库程序代码类型， 这里有数据模型、接口文档两种情况，根据上级的id来判断
    var langSec = document.querySelector('#langType');
    if(langSec){
      var pageDiv = langSec.parentElement.parentElement;
      var pageType = 0; // 1|数据模型;2|接口文档
      if(pageDiv?.id.includes('modelAppCodePage')){
        pageType = 1;
      }else if (pageDiv?.id.includes('apiCodePage')){
        pageType = 2;
      }
      var setDeftLangTypeBtn = document.querySelector('#setDeftLangType');
      if(!setDeftLangTypeBtn){
        var setDeftLangTypeDiv = createDivByHtml(
          `<button type="button" id="setDeftLangType" style="font-size: 100%;color:orange;">设为默认语言</button>`
        );
        setDeftLangTypeDiv.addEventListener('click', function () {
          if(pageType == 1)  sessionStorage.setItem('defaultModelLangType', langSec.value);
          if(pageType == 2)  sessionStorage.setItem('defaultApiLangType', langSec.value);
          createAlert(`已将“${langSec.value}”设为默认语言`, 'success', 1500);
        });
        langSec.parentElement.appendChild(setDeftLangTypeDiv);
      }
      var defaultLangType ;
      if(pageType == 1){
        defaultLangType = sessionStorage.getItem('defaultModelLangType')
      }else if (pageType == 2){
        defaultLangType = sessionStorage.getItem('defaultApiLangType')
      }
      if(defaultLangType){
        setTimeout(() => {
          langSec.value = defaultLangType;
          const changeEvent = new Event('change');
          langSec.dispatchEvent(changeEvent);
        }, 500);

      }
    }
  });
}

// 任务日志字体调大
function pmsLogLargeFont() {
  // 日志展示全部内容tip
  elmGetter.each('#changeTime > a', document, (logA) => {
    logA.title = logA.innerText
  })

  // 给日志列表标题增加工时合计值
  elmGetter.each('div.logDataContainer > div.searchInfo', document, (firstLog) => {
    var logDataContainer = firstLog.parentElement;
    var loglist = logDataContainer.querySelectorAll(" div.userLogDiv > div:nth-child(1) > table > tbody > tr:nth-child(2) > td");
    var logTitle = document.querySelector("div[id*=rwxqID_taskDetail_] > div:nth-child(2) > div.p-rwxq-left > div > div.tab1 > ul > li.selectedtab1 > a");
    var workHours = 0;
    loglist.forEach(td=>{
      var text = td.innerText;
      if(/(\d+\.\d+)小时/.test(text)){
        const matches = text.match(/\d+\.\d+/);
        workHours += new Number(matches[0]);
      }
    });
    logTitle.innerText = logTitle.innerText + '(' + parseFloat(parseFloat(workHours/8).toFixed(2)).toString()+'天)';
  });


  GM_addStyle(`/* 日志大字体 */
		div.taskcontent ol,ul{
			padding-left: 1rem;
		}
		div.taskcontent ol > li{
			list-style: auto;
		}
		div.taskcontent ul > li {
			list-style: disc;
		}
		div[id*="rwxqID_taskDetail_"] > div:nth-child(2) > div.p-rwxq-left > div > div.dataContainer {
				background:#fff !important;
		}

		div[id*="rwxqID_taskDetail_"] > div:nth-child(2) > div.p-rwxq-left > div > div.dataContainer > div {
				border: none;
		}
		.logDataContainer * {
				font-size: 14px !important;
		}
		div[id*="logList"] .logTable{
				border-bottom: 0px !important;
		}
		ul.tab > li * {
				font-size: 14px !important;
		}
		div.p-rwxq-right > div.p-rwxq-info-list > p > span,span>a{
				font-size: 14px !important;
		}
		strong{
				font-weight: bold;
		}
		button[data-menu-key="Save"] {
				color: red;
		}
		button.disabled[data-menu-key="Save"]{
		background: transparent;
		}

		.luckysheet-toolbar-combo-button{
		vertical-align: middle !important;
		}

		.luckysheet-toolbar-combo-button-inner-box, .luckysheet-toolbar-combo-button-outer-box {
		vertical-align: middle !important;
		}
		#changeLog{
		float: none !important;
		width: fit-content;
		}
		#changeTime{
			max-width: 400px;
			white-space: nowrap;
			overflow: hidden;
			text-overflow: ellipsis;
		}
		#changeTime > a:hover{
		background-color: bisque;
		}
		#changeTime > a{
		color: black;
		}
		.logtime {
			color: inherit !important;
			border-bottom: 2px #FFB951 solid;
			margin-bottom: 5px;
			list-style: decimal;
	}`)
}

// 子任务列表优化
function pmsChildTaskPerf() {

	//格式化主任务各种日期
  const dateSelectors = [
    'div[id*="ID_taskzrw"] > table.tmTable > tbody.bglsCont > tr> td:nth-child(4)',
    'div[id*="rwxqID_taskDetail"] > div:nth-child(3) > div.p-rwxq-right > div.p-rwxq-info-list > p:nth-child(10) > span',
    'div[id*="rwxqID_taskDetail"] > div:nth-child(3) > div.p-rwxq-right > div.p-rwxq-info-list > p:nth-child(11)> span',
    'div[id*="rwxqID_taskDetail"] > div:nth-child(3) > div.p-rwxq-right > div.p-rwxq-info-list > p:nth-child(12)> span',
    'div[id*="rwxqID_taskDetail"] > div:nth-child(3) > div.p-rwxq-right > div.p-rwxq-info-list > p:nth-child(19)> span',
    'div[id*="rwxqID_taskDetail"] > div:nth-child(3) > div.p-rwxq-right > div.p-rwxq-info-list > p:nth-child(20)> span',
    'div[id*="rwxqID_taskDetail"] > div:nth-child(3) > div.p-rwxq-right > div.p-rwxq-info-list > p:nth-child(21)> span',
    'div[id*="rwxqID_taskDetail"] > div:nth-child(3) > div.p-rwxq-right > div.p-rwxq-info-list > p:nth-child(22)> span',
    'div[id*="logList"] > div:nth-child(1) > div > div.logDataContainer > div > div:nth-child(1) > table > tbody > tr:nth-child(2) > td',
    'div[id*="logList"] > div:nth-child(1) > div > div.logDataContainer > div > div:nth-child(2) > div.tableContainer > table.logTable > tbody > tr:nth-child(2) > td:nth-child(1)',
  ];
  dateSelectors.forEach((v) => {
    elmGetter.each(v, document, (dateDom) => {
      if (/(\d{4})-*(\d{2})-*(\d{2})/.test(dateDom.innerText)) {
        dateDom.innerText = dateDom.innerText.replace(/(\d{4})-*(\d{2})-*(\d{2})/, '$1/$2/$3')
      }
    })
  })
  // 表头增加操作列
  elmGetter.each('div[id*="ID_taskzrw"] > table.tmTable > tbody:nth-child(1)', document, (titleTbody) => {
    var parent = titleTbody.querySelector('tr')
    var operBtn = parent.querySelector('th:last-child').cloneNode(true)
    operBtn.setAttribute('width', '8%')
    operBtn.setAttribute('title', '')
    operBtn.innerHTML = `操作`

    parent.appendChild(operBtn)
  })
  // 子任务增加操作列
  elmGetter.each('div[id*="ID_taskzrw"] > table.tmTable > tbody.bglsCont > tr', document, (parent) => {
    var pmsNumberDom = parent.querySelector('td:nth-child(1)')
    var statNameDom = parent.querySelector('td:nth-child(3)')
    var pmsEndDateDom = parent.querySelector('td:nth-child(4)')
    var exerDom = parent.querySelector('td:nth-child(5)')
    var taskId = null
    if (/(\d+)(?:\-.+)/.test(pmsNumberDom.innerText)) {
      taskId = pmsNumberDom.innerText.match(/(\d+)(?:\-.+)/)[1]
    }

    statNameDom.style.textAlign = 'center'
    pmsEndDateDom.style.textAlign = 'center'
    exerDom.style.textAlign = 'center'

    // 添加操作按钮
    var operBtn = exerDom.cloneNode(true)
    operBtn.style.textAlign = 'center'
    operBtn.innerHTML = ''

    //给任务状态增加颜色
    if (taskId) {
      var backgroudColorObj = {
        完成: '#bdf3bd',
        取消: '#d7d7d7',
        关闭: '#d7d7d7',
        待审核: '#ffd99b',
        测试中: '#ffd99b',
        开发中: '#ff9999',
        打开: '#ff4b4b',
      }
      if (Object.keys(backgroudColorObj).includes(statNameDom.innerText)) {
        statNameDom.style.backgroundColor = backgroudColorObj[statNameDom.innerText]
      }
      if (['打开', '开发中', '待审核'].includes(statNameDom.innerText)) {
        operBtn.innerHTML = `<a href="http://cowork.apexsoft.com.cn/plug-in/cowork/addTask.jsp?ID=${taskId}&GZDD=null&extWindow=false&PopupWin=false">编辑</a>`;
      }
    }
    parent.appendChild(operBtn)
  })

  // 隐藏难看的分割线
  elmGetter.each('div[id*="rwxqID_taskDetail_"]', document, (parent) => {
    var hr = parent.querySelector('hr')
    parent.removeChild(hr)
  })

  // 给分配人的任务列表增加任务跳转链接
  elmGetter.each(
    'div[id*="ID_userTask_"] > div > div.myTaskGrid.ac-grid > table > tbody > tr.p-table-data ',
    document,
    (parent) => {
      var pmsNumberDom = parent.querySelector('td:nth-child(1)')
      var pmsTitleDom = parent.querySelector('td:nth-child(2)')
      var statNameDom = parent.querySelector('td:nth-child(3)')
      pmsNumberDom.innerHTML = `<a href='http://cowork.apexsoft.com.cn/plug-in/cowork/taskDetail_new.jsp?ID=${pmsNumberDom.innerText}' target='_blank'>${pmsNumberDom.innerText}</a>`;
      pmsTitleDom.innerHTML = `<a href='http://cowork.apexsoft.com.cn/plug-in/cowork/taskDetail_new.jsp?ID=${pmsNumberDom.innerText}' target='_blank'>${pmsTitleDom.innerText}</a>`;

      //给任务状态增加颜色
      var backgroudColorObj = {
        完成: '#bdf3bd',
        取消: '#d7d7d7',
        关闭: '#d7d7d7',
        待审核: '#ffd99b',
        测试中: '#ffd99b',
        开发中: '#ff9999',
        打开: '#ff4b4b',
      }
      if (Object.keys(backgroudColorObj).includes(statNameDom.innerText)) {
        statNameDom.style.backgroundColor = backgroudColorObj[statNameDom.innerText]
      }
    }
  )

  // 给分配人的任务列表表头调整宽度
  elmGetter.each('div[id*="ID_userTask_"] > div > div.myTaskGrid.ac-grid > table > thead > tr', document, (parent) => {
    parent.querySelector('th:nth-child(1)').setAttribute('width', '5%')
    parent.querySelector('th:nth-child(2)').setAttribute('width', '40%')
    parent.querySelector('th:nth-child(3)').setAttribute('width', '5%')
    parent.querySelector('th:nth-child(4)').setAttribute('width', '5%')
    parent.querySelector('th:nth-child(5)').setAttribute('width', '5%')
    parent.querySelector('th:nth-child(6)').setAttribute('width', '5%')
    parent.querySelector('th:nth-child(7)').setAttribute('width', '5%')
  })

  // 移除任务信息下的分割线
  elmGetter.each('div[id*="rwxqID_taskDetail_"] > div:nth-child(2) > div.p-rwxq-right', document, (parent) => {
    var hr = parent.querySelector('div:nth-child(2)')
    parent.removeChild(hr)
  })

  // 隐藏 分配人的任务列表 多余的分页控件
  elmGetter.each('div[id*="ID_userTask_"] > div.box', document, (parent) => {
    var pagerCountDom = parent.querySelector('div.pager-cont')
    if (pagerCountDom) {
      parent.removeChild(pagerCountDom)
    }
  })

  // 给子任务列表增加排序功能
  elmGetter.each('div[id*="ID_taskzrw"] > table.tmTable', document, (table) => {
    // 获取表格头部的所有单元格
    const headers = table.querySelectorAll('th')

    // 为每个表头添加点击事件监听器，以对其内容进行排序
    headers.forEach((header) => {
      let reverse = false
      header.style.cursor = 'pointer'
      header.title = '点击排序当页任务'
      header.addEventListener('click', () => {
        // 获取表头单元格的数据索引
        const index = header.cellIndex

        // 获取表格主体的所有行
        const rows = table.querySelectorAll('tbody.bglsCont tr')

        // 将行按指定列的内容进行排序
        // 将行按指定列的内容进行排序
        Array.from(rows)
          .sort((a, b) => {
            const aValue = a.children[index].textContent
            const bValue = b.children[index].textContent
            if (aValue.replace(/\s/g, '').length === 0 && bValue.replace(/\s/g, '').length !== 0) {
              return 1
            } else if (aValue.replace(/\s/g, '').length !== 0 && bValue.replace(/\s/g, '').length === 0) {
              return -1
            } else if (reverse) {
              return aValue.localeCompare(bValue)
              if (bValue == undefined || bValue == '') return -1
            } else {
              return bValue.localeCompare(aValue)
              if (bValue == undefined || bValue == '') return 1
            }
          })
          .forEach((row) => {
            table.querySelector('tbody.bglsCont').appendChild(row)
          })

        // 切换 reverse 标志
        reverse = !reverse
      })
    })
  })


  GM_addStyle(`
		/* 子任务列表选中状态 */
    div[id*="ID_userTask_"] > div.box > div.pager-cont{
			display: none;
    }
		div[id*="ID_taskzrw"] > table.tmTable > tbody.bglsCont > tr:hover {
			background-color: #99bbe842;
		}
		/* 分配人的任务列表任务主题居左 */
		div[id*="ID_userTask_"] > div > div.myTaskGrid.ac-grid > table > tbody > tr > td:nth-child(2) {
			text-align: left;
		}
		/*分配人的任务列表样式修正*/
		.p-table-data tr.hover td {
			background-color: inherit ;
		}
		.p-table-bmbd tr.hover td {
			background-color: inherit ;
		}
		.box table tr:hover {
			background: #99bbe842;
		}
	`);
}

// 文档打开界面优化
function pmsDocumentPagePerf() {
  elmGetter.each('div.extra:has(section.logo)', document, (logo) => {
    logo.style.display = 'none'
  })
}


let currentTrigger = null;
// 计算最佳位置并显示提示框
function showTooltip(trigger, content) {
  if (!trigger || !content) return

  currentTrigger = trigger

  // 尝试获取已有的提示框，如果没有则自动创建一个
  let tooltip = document.getElementById('dynamic-tooltip')
  if (!tooltip) {
    tooltip = document.createElement('div')
    tooltip.id = 'dynamic-tooltip'
    tooltip.className = 'tooltip-content'
    document.body.appendChild(tooltip)
  }

  // 先设置内容
  tooltip.innerHTML = content

  // 获取触发元素的位置信息
  const triggerRect = trigger.getBoundingClientRect()
  const viewportWidth = window.innerWidth
  const viewportHeight = window.innerHeight

  // 提示框尺寸（估算值）
  const tooltipPadding = 16
  const tooltipWidth = Math.max(content.length * 10, 80) // 粗略估算宽度
  const tooltipHeight = 36 // 大概高度

  let left, top, position

  // 策略：优先显示在下方，其次是上方，再调整左右以防超出屏幕

  // 1. 尝试显示在下方（bottom 方向）
  left = triggerRect.left + triggerRect.width / 2 - tooltipWidth / 2
  top = triggerRect.bottom + 10

  position = 'bottom'

  // 检查是否超出左右边界
  if (left < 10) left = 10
  if (left + tooltipWidth > viewportWidth - 10) {
    left = viewportWidth - tooltipWidth - 10
  }

  // 检查是否超出下边界（一般不会，因为我们是在下方显示）
  if (top + tooltipHeight > viewportHeight - 10) {
    // 如果下方放不下，则尝试显示在上方
    position = 'top'
    top = triggerRect.top - tooltipHeight - 10
    left = triggerRect.left + triggerRect.width / 2 - tooltipWidth / 2

    if (left < 10) left = 10
    if (left + tooltipWidth > viewportWidth - 10) {
      left = viewportWidth - tooltipWidth - 10
    }

    // 如果上方也放不下（极少数情况），则贴边显示
    if (top < 10) top = 10
  }

  // 应用位置
  tooltip.style.left = `${left}px`
  tooltip.style.top = `${top}px`

  // 显示提示框
  tooltip.classList.add('show')
}

// 隐藏提示框
function hideTooltip() {
  let tooltip = document.getElementById('dynamic-tooltip')
  tooltip.classList.remove('show');
  currentTrigger = null;
}
function bindToolTip(element) {
  if (element.getAttribute('data-tooltip')) {
      element.addEventListener('mouseenter', () => showTooltip(element, element.getAttribute('data-tooltip')));
      element.addEventListener('mouseleave',  () => hideTooltip());
  }
}


function Work() {
  configIdList.forEach((v) => {
    if (t.get(v.id) == true) {
      var func = eval(v.id)
      func()
    }
  });
}

function pmsWholeFontPerf() {
  GM_addStyle(`
	 /* 优化接口说明样式 */
	 .w-e-text-container [data-slate-editor] {
		padding: 0px 10px 20px 10px !important;
	}

	/* luckysheet编辑时的字体 */
	#luckysheet-rich-text-editor{
		font-size: inherit;
		font-family: inherit;
	}

	#luckysheet-input-box {
			padding-top: 2px !important;
	}
	#luckysheet-rich-text-editor span {
			font-size: 12pt !important;
	}

	/* 菜单按钮字体 */
	 .x-btn-text, .x-menu-item-text, .x-combo-list-item, .x-form-field, .x-window-tl .x-window-header ,a.btn, .user-menu-ml, #user .user-link ,#user .user-name , #notificationMore a
	 , div[id*="ID_apiDesign_"] > table td, .logtime{
		 font-family: system-ui, Verdana, Arial, Helvetica, AppleGothic, sans-serif !important;
	 }
	 .logtime::marker {
		font-size: 14px;
	}
	.log{
		font-size: 14px;
	}

	/*monoca编辑器代码字体*/
	.view-lines.monaco-mouse-cursor-text span,.sticky-widget-lines span,.monaco-editor .margin-view-overlays .line-numbers {
		font-family: ui-sans-serif, monospace, Consolas, "Courier New" !important ;
		font-size: 0.9rem;
	}


  #apiDoc{
    width: 100% !important;
  }
	body { font-size: 12px;}
	div:not([class]):not([id]):not([style]), form:not([class]):not([id]):not([style]), img:not([class]):not([id]):not([style]), h1:not([class]):not([id]):not([style]), h2:not([class]):not([id]):not([style]), h3:not([class]):not([id]):not([style]), ul:not([class]):not([id]):not([style]), li:not([class]):not([id]):not([style]), p:not([class]):not([id]):not([style]), span:not([class]):not([id]):not([style]), a:not([class]):not([id]):not([style]), dl:not([class]):not([id]):not([style]), dt:not([class]):not([id]):not([style]), dd:not([class]):not([id]):not([style]), input:not([class]):not([id]):not([style]), textarea:not([class]):not([id]):not([style]) { font-size: inherit !important;}
	h1, h2, h3, h4, h5, h6 {color: #2f332a;font-weight: bold;font-family: Helvetica, Arial, sans-serif;padding-bottom: 5px;}
	h1 , h1 span{font-size: 24px !important;line-height: 34px;text-align: center;}
	h2 , h2 span{font-size: 14px !important;line-height: 24px;padding-top: 5px;}
	h6 , h6 span{font-weight: normal;font-size: 12px !important;letter-spacing: 1px;line-height: 24px;text-align: center;}
  `)
}

;(async function () {
  'use strict'
  registerMenu()
  Work()


  // 添加自定义提示弹窗，使用：元素创建时，class 添加 tooltip-trigger， 增加data-tooltip属性即可

  GM_addStyle(`
  /* 提示框基础样式 */
  .tooltip-content {
      position: fixed; /* 必须用 fixed 才能相对于视口定位 */
      background: #222;
      color: white;
      padding: 8px 16px;
      border-radius: 10px;
      font-size: 14px;
      white-space: nowrap;
      z-index: 1000;
      opacity: 0;
      visibility: hidden;
      transition: all 0.2s ease;
      box-shadow: 0 2px 8px rgba(0,0,0,0.15);
      pointer-events: none;
  }

  /* 显示状态 */
  .tooltip-content.show {
      opacity: 1;
      visibility: visible;
  }

  /* 简单箭头（可选，如需要可加上） */
  .tooltip-content::after {
      content: '';
      position: absolute;
      width: 0;
      height: 0;
      border: 6px solid transparent;
  }
  `);

  window.addEventListener('resize', hideTooltip);
})()
